Determine what attributes were changed in Rails after_save callback?
Rails 5.1+
Use saved_change_to_published?
:
class SomeModel < ActiveRecord::Base after_update :send_notification_after_change def send_notification_after_change Notification.send(…) if (saved_change_to_published? && self.published == true) endend
Or if you prefer, saved_change_to_attribute?(:published)
.
Rails 3–5.1
Warning
This approach works through Rails 5.1 (but is deprecated in 5.1 and has breaking changes in 5.2). You can read about the change in this pull request.
In your after_update
filter on the model you can use _changed?
accessor. So for example:
class SomeModel < ActiveRecord::Base after_update :send_notification_after_change def send_notification_after_change Notification.send(...) if (self.published_changed? && self.published == true) endend
It just works.
For those who want to know the changes just made in an after_save
callback:
Rails 5.1 and greater
model.saved_changes
Rails < 5.1
model.previous_changes
Also see: http://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-previous_changes
To anyone seeing this later on, as it currently (Aug. 2017) tops google: It is worth mentioning, that this behavior will be altered in Rails 5.2, and has deprecation warnings as of Rails 5.1, as ActiveModel::Dirty changed a bit.
What do I change?
If you're using attribute_changed?
method in the after_*
-callbacks, you'll see a warning like:
DEPRECATION WARNING: The behavior of
attribute_changed?
inside of after callbacks will be changing in the next version of Rails. The new return value will reflect the behavior of calling the method aftersave
returned (e.g. the opposite of what it returns now). To maintain the current behavior, usesaved_change_to_attribute?
instead. (called from some_callback at /PATH_TO/app/models/user.rb:15)
As it mentions, you could fix this easily by replacing the function with saved_change_to_attribute?
. So for example, name_changed?
becomes saved_change_to_name?
.
Likewise, if you're using the attribute_change
to get the before-after values, this changes as well and throws the following:
DEPRECATION WARNING: The behavior of
attribute_change
inside of after callbacks will be changing in the next version of Rails. The new return value will reflect the behavior of calling the method aftersave
returned (e.g. the opposite of what it returns now). To maintain the current behavior, usesaved_change_to_attribute
instead. (called from some_callback at /PATH_TO/app/models/user.rb:20)
Again, as it mentions, the method changes name to saved_change_to_attribute
which returns ["old", "new"]
.or use saved_changes
, which returns all the changes, and these can be accessed as saved_changes['attribute']
.