Rails 3 check if attribute changed
Need to check if a block of attributes has changed before update in Rails 3.
street1, street2, city, state, zipcode
I know I could use someth开发者_开发技巧ing like
if @user.street1 != params[:user][:street1]
then do something....
end
But that piece of code will be REALLY long. Is there a cleaner way?
Check out ActiveModel::Dirty (available on all models by default). The documentation is really good, but it lets you do things such as:
@user.street1_changed? # => true/false
This is how I solved the problem of checking for changes in multiple attributes.
attrs = ["street1", "street2", "city", "state", "zipcode"]
if (@user.changed & attrs).any?
then do something....
end
The changed
method returns an array of the attributes changed for that object.
Both @user.changed
and attrs
are arrays so I can get the intersection (see ary & other ary
method). The result of the intersection is an array. By calling any?
on the array, I get true if there is at least one intersection.
Also very useful, the changed_attributes
method returns a hash of the attributes with their original values and the changes
returns a hash of the attributes with their original and new values (in an array).
You can check APIDock for which versions supported these methods.
http://apidock.com/rails/ActiveModel/Dirty
For rails 5.1+ callbacks
As of Ruby on Rails 5.1, the attribute_changed?
and attribute_was
ActiveRecord methods will be deprecated
Use saved_change_to_attribute?
instead of attribute_changed?
@user.saved_change_to_street1? # => true/false
More examples here
ActiveModel::Dirty
didn't work for me because the @model.update_attributes()
hid the changes. So this is how I detected changes it in an update
method in a controller:
def update
@model = Model.find(params[:id])
detect_changes
if @model.update_attributes(params[:model])
do_stuff if attr_changed?
end
end
private
def detect_changes
@changed = []
@changed << :attr if @model.attr != params[:model][:attr]
end
def attr_changed?
@changed.include :attr
end
If you're trying to detect a lot of attribute changes it could get messy though. Probably shouldn't do this in a controller, but meh.
Above answers are better but yet for knowledge we have another approch as well, Lets 'catagory' column value changed for an object (@design),
@design.changes.has_key?('catagory')
The .changes will return a hash with key as column's name and values as a array with two values [old_value, new_value] for each columns. For example catagory for above is changed from 'ABC' to 'XYZ' of @design,
@design.changes # => {}
@design.catagory = 'XYZ'
@design.changes # => { 'catagory' => ['ABC', 'XYZ'] }
For references change in ROR
精彩评论