PageRenderTime 23ms CodeModel.GetById 29ms RepoModel.GetById 0ms app.codeStats 0ms

/activerecord/lib/active_record/callbacks.rb

https://github.com/stephanwehner/rails
Ruby | 362 lines | 83 code | 31 blank | 248 comment | 21 complexity | 0aa876003880edacb1f54d58bff1fcca MD5 | raw file
  1. require 'observer'
  2. module ActiveRecord
  3. # Callbacks are hooks into the lifecycle of an Active Record object that allow you to trigger logic
  4. # before or after an alteration of the object state. This can be used to make sure that associated and
  5. # dependent objects are deleted when +destroy+ is called (by overwriting +before_destroy+) or to massage attributes
  6. # before they're validated (by overwriting +before_validation+). As an example of the callbacks initiated, consider
  7. # the <tt>Base#save</tt> call for a new record:
  8. #
  9. # * (-) <tt>save</tt>
  10. # * (-) <tt>valid</tt>
  11. # * (1) <tt>before_validation</tt>
  12. # * (2) <tt>before_validation_on_create</tt>
  13. # * (-) <tt>validate</tt>
  14. # * (-) <tt>validate_on_create</tt>
  15. # * (3) <tt>after_validation</tt>
  16. # * (4) <tt>after_validation_on_create</tt>
  17. # * (5) <tt>before_save</tt>
  18. # * (6) <tt>before_create</tt>
  19. # * (-) <tt>create</tt>
  20. # * (7) <tt>after_create</tt>
  21. # * (8) <tt>after_save</tt>
  22. #
  23. # That's a total of eight callbacks, which gives you immense power to react and prepare for each state in the
  24. # Active Record lifecycle. The sequence for calling <tt>Base#save</tt> an existing record is similar, except that each
  25. # <tt>_on_create</tt> callback is replaced by the corresponding <tt>_on_update</tt> callback.
  26. #
  27. # Examples:
  28. # class CreditCard < ActiveRecord::Base
  29. # # Strip everything but digits, so the user can specify "555 234 34" or
  30. # # "5552-3434" or both will mean "55523434"
  31. # def before_validation_on_create
  32. # self.number = number.gsub(/[^0-9]/, "") if attribute_present?("number")
  33. # end
  34. # end
  35. #
  36. # class Subscription < ActiveRecord::Base
  37. # before_create :record_signup
  38. #
  39. # private
  40. # def record_signup
  41. # self.signed_up_on = Date.today
  42. # end
  43. # end
  44. #
  45. # class Firm < ActiveRecord::Base
  46. # # Destroys the associated clients and people when the firm is destroyed
  47. # before_destroy { |record| Person.destroy_all "firm_id = #{record.id}" }
  48. # before_destroy { |record| Client.destroy_all "client_of = #{record.id}" }
  49. # end
  50. #
  51. # == Inheritable callback queues
  52. #
  53. # Besides the overwritable callback methods, it's also possible to register callbacks through the use of the callback macros.
  54. # Their main advantage is that the macros add behavior into a callback queue that is kept intact down through an inheritance
  55. # hierarchy. Example:
  56. #
  57. # class Topic < ActiveRecord::Base
  58. # before_destroy :destroy_author
  59. # end
  60. #
  61. # class Reply < Topic
  62. # before_destroy :destroy_readers
  63. # end
  64. #
  65. # Now, when <tt>Topic#destroy</tt> is run only +destroy_author+ is called. When <tt>Reply#destroy</tt> is run, both +destroy_author+ and
  66. # +destroy_readers+ are called. Contrast this to the situation where we've implemented the save behavior through overwriteable
  67. # methods:
  68. #
  69. # class Topic < ActiveRecord::Base
  70. # def before_destroy() destroy_author end
  71. # end
  72. #
  73. # class Reply < Topic
  74. # def before_destroy() destroy_readers end
  75. # end
  76. #
  77. # In that case, <tt>Reply#destroy</tt> would only run +destroy_readers+ and _not_ +destroy_author+. So, use the callback macros when
  78. # you want to ensure that a certain callback is called for the entire hierarchy, and use the regular overwriteable methods
  79. # when you want to leave it up to each descendant to decide whether they want to call +super+ and trigger the inherited callbacks.
  80. #
  81. # *IMPORTANT:* In order for inheritance to work for the callback queues, you must specify the callbacks before specifying the
  82. # associations. Otherwise, you might trigger the loading of a child before the parent has registered the callbacks and they won't
  83. # be inherited.
  84. #
  85. # == Types of callbacks
  86. #
  87. # There are four types of callbacks accepted by the callback macros: Method references (symbol), callback objects,
  88. # inline methods (using a proc), and inline eval methods (using a string). Method references and callback objects are the
  89. # recommended approaches, inline methods using a proc are sometimes appropriate (such as for creating mix-ins), and inline
  90. # eval methods are deprecated.
  91. #
  92. # The method reference callbacks work by specifying a protected or private method available in the object, like this:
  93. #
  94. # class Topic < ActiveRecord::Base
  95. # before_destroy :delete_parents
  96. #
  97. # private
  98. # def delete_parents
  99. # self.class.delete_all "parent_id = #{id}"
  100. # end
  101. # end
  102. #
  103. # The callback objects have methods named after the callback called with the record as the only parameter, such as:
  104. #
  105. # class BankAccount < ActiveRecord::Base
  106. # before_save EncryptionWrapper.new
  107. # after_save EncryptionWrapper.new
  108. # after_initialize EncryptionWrapper.new
  109. # end
  110. #
  111. # class EncryptionWrapper
  112. # def before_save(record)
  113. # record.credit_card_number = encrypt(record.credit_card_number)
  114. # end
  115. #
  116. # def after_save(record)
  117. # record.credit_card_number = decrypt(record.credit_card_number)
  118. # end
  119. #
  120. # alias_method :after_find, :after_save
  121. #
  122. # private
  123. # def encrypt(value)
  124. # # Secrecy is committed
  125. # end
  126. #
  127. # def decrypt(value)
  128. # # Secrecy is unveiled
  129. # end
  130. # end
  131. #
  132. # So you specify the object you want messaged on a given callback. When that callback is triggered, the object has
  133. # a method by the name of the callback messaged. You can make these callbacks more flexible by passing in other
  134. # initialization data such as the name of the attribute to work with:
  135. #
  136. # class BankAccount < ActiveRecord::Base
  137. # before_save EncryptionWrapper.new("credit_card_number")
  138. # after_save EncryptionWrapper.new("credit_card_number")
  139. # after_initialize EncryptionWrapper.new("credit_card_number")
  140. # end
  141. #
  142. # class EncryptionWrapper
  143. # def initialize(attribute)
  144. # @attribute = attribute
  145. # end
  146. #
  147. # def before_save(record)
  148. # record.send("#{@attribute}=", encrypt(record.send("#{@attribute}")))
  149. # end
  150. #
  151. # def after_save(record)
  152. # record.send("#{@attribute}=", decrypt(record.send("#{@attribute}")))
  153. # end
  154. #
  155. # alias_method :after_find, :after_save
  156. #
  157. # private
  158. # def encrypt(value)
  159. # # Secrecy is committed
  160. # end
  161. #
  162. # def decrypt(value)
  163. # # Secrecy is unveiled
  164. # end
  165. # end
  166. #
  167. # The callback macros usually accept a symbol for the method they're supposed to run, but you can also pass a "method string",
  168. # which will then be evaluated within the binding of the callback. Example:
  169. #
  170. # class Topic < ActiveRecord::Base
  171. # before_destroy 'self.class.delete_all "parent_id = #{id}"'
  172. # end
  173. #
  174. # Notice that single quotes (') are used so the <tt>#{id}</tt> part isn't evaluated until the callback is triggered. Also note that these
  175. # inline callbacks can be stacked just like the regular ones:
  176. #
  177. # class Topic < ActiveRecord::Base
  178. # before_destroy 'self.class.delete_all "parent_id = #{id}"',
  179. # 'puts "Evaluated after parents are destroyed"'
  180. # end
  181. #
  182. # == The +after_find+ and +after_initialize+ exceptions
  183. #
  184. # Because +after_find+ and +after_initialize+ are called for each object found and instantiated by a finder, such as <tt>Base.find(:all)</tt>, we've had
  185. # to implement a simple performance constraint (50% more speed on a simple test case). Unlike all the other callbacks, +after_find+ and
  186. # +after_initialize+ will only be run if an explicit implementation is defined (<tt>def after_find</tt>). In that case, all of the
  187. # callback types will be called.
  188. #
  189. # == <tt>before_validation*</tt> returning statements
  190. #
  191. # If the returning value of a +before_validation+ callback can be evaluated to +false+, the process will be aborted and <tt>Base#save</tt> will return +false+.
  192. # If Base#save! is called it will raise a ActiveRecord::RecordInvalid exception.
  193. # Nothing will be appended to the errors object.
  194. #
  195. # == Canceling callbacks
  196. #
  197. # If a <tt>before_*</tt> callback returns +false+, all the later callbacks and the associated action are cancelled. If an <tt>after_*</tt> callback returns
  198. # +false+, all the later callbacks are cancelled. Callbacks are generally run in the order they are defined, with the exception of callbacks
  199. # defined as methods on the model, which are called last.
  200. #
  201. # == Transactions
  202. #
  203. # The entire callback chain of a +save+, <tt>save!</tt>, or +destroy+ call runs
  204. # within a transaction. That includes <tt>after_*</tt> hooks. If everything
  205. # goes fine a COMMIT is executed once the chain has been completed.
  206. #
  207. # If a <tt>before_*</tt> callback cancels the action a ROLLBACK is issued. You
  208. # can also trigger a ROLLBACK raising an exception in any of the callbacks,
  209. # including <tt>after_*</tt> hooks. Note, however, that in that case the client
  210. # needs to be aware of it because an ordinary +save+ will raise such exception
  211. # instead of quietly returning +false+.
  212. module Callbacks
  213. extend ActiveSupport::DependencyModule
  214. CALLBACKS = %w(
  215. after_find after_initialize before_save after_save before_create after_create before_update after_update before_validation
  216. after_validation before_validation_on_create after_validation_on_create before_validation_on_update
  217. after_validation_on_update before_destroy after_destroy
  218. )
  219. included do
  220. extend Observable
  221. [:create_or_update, :valid?, :create, :update, :destroy].each do |method|
  222. alias_method_chain method, :callbacks
  223. end
  224. include ActiveSupport::Callbacks
  225. define_callbacks *CALLBACKS
  226. end
  227. # Is called when the object was instantiated by one of the finders, like <tt>Base.find</tt>.
  228. #def after_find() end
  229. # Is called after the object has been instantiated by a call to <tt>Base.new</tt>.
  230. #def after_initialize() end
  231. # Is called _before_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save).
  232. def before_save() end
  233. # Is called _after_ <tt>Base.save</tt> (regardless of whether it's a +create+ or +update+ save).
  234. # Note that this callback is still wrapped in the transaction around +save+. For example, if you
  235. # invoke an external indexer at this point it won't see the changes in the database.
  236. #
  237. # class Contact < ActiveRecord::Base
  238. # after_save { logger.info( 'New contact saved!' ) }
  239. # end
  240. def after_save() end
  241. def create_or_update_with_callbacks #:nodoc:
  242. return false if callback(:before_save) == false
  243. if result = create_or_update_without_callbacks
  244. callback(:after_save)
  245. end
  246. result
  247. end
  248. private :create_or_update_with_callbacks
  249. # Is called _before_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists).
  250. def before_create() end
  251. # Is called _after_ <tt>Base.save</tt> on new objects that haven't been saved yet (no record exists).
  252. # Note that this callback is still wrapped in the transaction around +save+. For example, if you
  253. # invoke an external indexer at this point it won't see the changes in the database.
  254. def after_create() end
  255. def create_with_callbacks #:nodoc:
  256. return false if callback(:before_create) == false
  257. result = create_without_callbacks
  258. callback(:after_create)
  259. result
  260. end
  261. private :create_with_callbacks
  262. # Is called _before_ <tt>Base.save</tt> on existing objects that have a record.
  263. def before_update() end
  264. # Is called _after_ <tt>Base.save</tt> on existing objects that have a record.
  265. # Note that this callback is still wrapped in the transaction around +save+. For example, if you
  266. # invoke an external indexer at this point it won't see the changes in the database.
  267. def after_update() end
  268. def update_with_callbacks(*args) #:nodoc:
  269. return false if callback(:before_update) == false
  270. result = update_without_callbacks(*args)
  271. callback(:after_update)
  272. result
  273. end
  274. private :update_with_callbacks
  275. # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call).
  276. def before_validation() end
  277. # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call).
  278. def after_validation() end
  279. # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects
  280. # that haven't been saved yet (no record exists).
  281. def before_validation_on_create() end
  282. # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on new objects
  283. # that haven't been saved yet (no record exists).
  284. def after_validation_on_create() end
  285. # Is called _before_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on
  286. # existing objects that have a record.
  287. def before_validation_on_update() end
  288. # Is called _after_ <tt>Validations.validate</tt> (which is part of the <tt>Base.save</tt> call) on
  289. # existing objects that have a record.
  290. def after_validation_on_update() end
  291. def valid_with_callbacks? #:nodoc:
  292. return false if callback(:before_validation) == false
  293. if new_record? then result = callback(:before_validation_on_create) else result = callback(:before_validation_on_update) end
  294. return false if false == result
  295. result = valid_without_callbacks?
  296. callback(:after_validation)
  297. if new_record? then callback(:after_validation_on_create) else callback(:after_validation_on_update) end
  298. return result
  299. end
  300. # Is called _before_ <tt>Base.destroy</tt>.
  301. #
  302. # Note: If you need to _destroy_ or _nullify_ associated records first,
  303. # use the <tt>:dependent</tt> option on your associations.
  304. def before_destroy() end
  305. # Is called _after_ <tt>Base.destroy</tt> (and all the attributes have been frozen).
  306. #
  307. # class Contact < ActiveRecord::Base
  308. # after_destroy { |record| logger.info( "Contact #{record.id} was destroyed." ) }
  309. # end
  310. def after_destroy() end
  311. def destroy_with_callbacks #:nodoc:
  312. return false if callback(:before_destroy) == false
  313. result = destroy_without_callbacks
  314. callback(:after_destroy)
  315. result
  316. end
  317. private
  318. def callback(method)
  319. result = run_callbacks(method) { |result, object| false == result }
  320. if result != false && respond_to_without_attributes?(method)
  321. result = send(method)
  322. end
  323. notify(method)
  324. return result
  325. end
  326. def notify(method) #:nodoc:
  327. self.class.changed
  328. self.class.notify_observers(method, self)
  329. end
  330. end
  331. end