WARNING. after_save is fired on both creation and update, but always after the more specific after_create and after_update callbacks, regardless of the order in which the macro calls are fired.
NOTE: The before_destroy callback must be placed before dependent: :destroy bindings (or use the prepend: true option) to ensure that they are executed before the entries are removed with dependent: :destroy.
after_initialize and after_find
The after_initialize callback is called whenever an Active Record object is instantiated, either directly by using new, or when a record is loaded from the database. It can be useful to avoid having to directly override the Active Record initialize method.
The after_find callback will be called whenever Active Record loads a record from the database. after_find is called before after_initialize if both are defined.
The after_initialize and after_find callbacks do not have a before_* pair, but they can be registered like other Active Record callbacks.
class User<ApplicationRecord
after_initialize do |user|
puts “You have initialized an object!”
end
after_find do |user|
puts “You have found an object!”
end
end
>> User.new
You have initialized an object!
=> #<User id: nil>
>> User.first
You have found an object!
You have initialized an object!
=> #<User id: 1>
after_touch
The after_touch callback will be called when touch is called on an Active Record object.
class User<ApplicationRecord
after_touch do |user|
puts “You have touched an object”
end
end
>> u = User.create(name: ‘Kuldeep’)
=> #<User id: 1, name: “Kuldeep”, created_at: “2013-11-25 12:17:49”, updated_at: “2013-11-25 12:17:49”>
>>u.touch
You have touched an object
=> true
It can be used in conjunction with belongs_to:
class Employee < ApplicationRecord
belongs_to :company, touch: true
after_touch do
puts ‘An Employee was touched’
end
end
classCompany < ApplicationRecord
has_many:employees
after_touch :log_when_employees_or_company_touched
private
def log_when_employees_or_company_touched
puts ‘Employee/Company was touched’
end
end
>> @employee = Employee.last
=> #<Employee id: 1, company_id: 1, created_at: “2013-11-25 17:04:22”, updated_at: “2013-11-25 17:05:05”>
# calls @employee.company.touch
>> @employee.touch
Employee/Company was touched
An employee was touched
=> true
Running callbacks
The following methods fire callbacks:
create
create!
destroy
destroy!
destroy_all
save
save!
save(validate: false)
toggle!
update_attribute
update
update!
valid?
Additionally, the after_find callback is fired by the following find methods:
all
first
find
find_by
find_by_*
find_by_*!
find_by_sql
last
The after_initialize callback is fired whenever a new class object is initialized.
NOTE: The find_by_* and find_by_* methods! these are dynamic lookup methods generated automatically for each attribute. Learn more about them in the Dynamic Search section.
Skipping callbacks
Similar to validations, it is also possible to skip callbacks using the following methods.
decrement
decrement_counter
delete
delete_all
increment
increment_counter
toggle
touch
update_column
update_columns
update_all
update_counters
However, these methods must be used with care as important business rules and application logic can be contained in callbacks. Skipping them without understanding the possible consequences can lead to invalid data.
Interrupt execution
As soon as you have registered new callbacks in your models, they will be queued for execution. This queue includes all your model validations, registered callbacks, and database operations to perform.
The entire chain of callbacks is packaged into an operation. If any callback throws an exception, the running chain is aborted and ROLLBACK is started. To intentionally stop a chain, use:
throw :abort
WARNING. Throwing an arbitrary exception can break code that assumes that save and the like will not fail like this. The ActiveRecord::Rollback exception tells Active Record a bit more precisely that a rollback is in progress. It is picked up from within, but does not rethrow the exception.
WARNING. Any exception other than ActiveRecord::Rollback or ActiveRecord::RecordInvalid will be rethrown by Rails after the callback chain breaks. Throwing an exception other than ActiveRecord::Rollback or ActiveRecord::RecordInvalid can break code that doesn’t expect methods like save and update_attributes (which usually try to return true or false) to throw an exception.
Relationship Callbacks
Callbacks work with relationships between models, and can even be defined by them. Imagine an example where a user has many articles. The user’s articles must be destroyed if the user is destroyed. Let’s add an after_destroy callback to the User model through its relationship with the Article model.
Conditional callbacks
As with validations, it is possible to make a callback method call conditional depending on a given predicate. This is done using the :if and :unless options, which can take a character, a Proc, or an array. The :if option should be used to determine under what conditions the callback should be called. If you want to specify conditions under which the callback should not be called, use the :unless option.
Using :if and :unless with a symbol
The :if and :unless options can be bound to a symbol corresponding to the name of the predicate method that will be called just before the callback is called. When using the :if option, the callback will not be executed if the predicate method returns false; when using the :unless option, the callback will not be executed if the predicate method returns true. This is the most common option. When using this form of registration, it is also possible to register several different predicates that will be called to check if the callback should run.
classOrder < ApplicationRecord
before_save :normalize_card_number, if: :paid_with_card?
end
Using :if and :unless with Proc
Finally, you can bind :if and :unless to the Proc object. This option is most suitable when writing short methods, usually one-liners.
classOrder < ApplicationRecord
before_save :normalize_card_number,
if: Proc.new { |order| order.paid_with_card? }
end
Compound conditions for callbacks
When writing conditional callbacks, it is possible to mix :if and :unless in the same callback declaration.
class Comment < ApplicationRecord
after_create :send_email_to_author, if: :author_wants_emails?,
unless: Proc.new { |comment| comment.article.ignore_comments? }
end
Callback classes
Sometimes the callback methods you write are useful enough to be reused in other models. Active Record makes it possible to create classes that include callback methods so that it becomes very easy to reuse them.
Here is an example where a class is created with an after_destroy callback for the PictureFile model:
class PictureFileCallbacks
def after_destroy(picture_file)
if File.exist?(picture_file.filepath)
File.delete(picture_file.filepath)
end
end
end
When declared within a class, as above, the callback methods receive the model object as a parameter. Now we can use the callback class in the model:
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks.new
end
Note that we need to instantiate a new PictureFileCallbacks object after we have declared our callback as a separate method. This is especially useful if callbacks use the state of an object instance. Often, however, it is more appropriate to declare it as a class method.
class PictureFileCallbacks
def self.after_destroy(picture_file)
if File.exist?(picture_file.filepath)
File.delete(picture_file.filepath)
end
end
end
If the callback method is declared this way, there is no need to instantiate the PictureFileCallbacks object.
class PictureFile < ApplicationRecord
after_destroy PictureFileCallbacks
end
Inside your callback class, you can create as many callbacks as you like.