Track changes when updating a record - ruby-on-rails

How do I check if the data is changed when I edit a record?
So before update
game.player=1
after update / edit
game.player=2
for example
how to track changes (check if changed) and do something in ruby on rails, when the data is changed.

Have a look at ActiveModel::Dirty
You can check if a model has been changed by doing:
game.changed?
Or an individual field like:
game.player_changed?
Both return a boolean value.

All changes are also kept in a hash. This comes in handy if you want to use the values.
game.changes #=> {:player => [1,2]}

Related

Ignore a column when using `.changed?` in rails

I want to use the .changed? method to check if a record has changed. The problem is that one of the fields will always be different. I would like to ignore the field. Something like:
record.changed?.except(:field_to_ignore)
How can I solve this?
ActiveModel::Dirty gives you a list of all the attributes that have changed via the changed method. So you could do something like
record.changed.reject { |attr| attr == 'field_to_ignore' }.size > 0
Read more about changed method here
EDITED
A simple solution to this is to use the same changed? functionality from ActiveModel::Dirty, so let's say that the attribute you don't want to take into account is x, with that said you can do something like this:
atttibutes_changed = record.changed_attributes.keys
atttibutes_changed.size > 1 || !atttibutes_changed.include?('x')
The above condition means: if more than one attribute changed or in case one changed need to be different from x. changed_attributes returns a hash with all the attributes that changed and his values (before change).

Fake a change for ActiveModel dirty or mimic 'touching' a column?

I can't think of a better way to title this Sorry!
Ultimately I have a callback that 99% of the time I only want to run when a particular list of attributes get changed. But in a couple of cases I'd love to be able to by pass my return unless previous_changes & watched_attributes.
Is there any way to mock a change to a particular attribute? Somehow set model.attribute_changed? to true?
I've been using model.touch but updated_at is a column I deliberately want to ignore.
Yes, you can check whether your attribute is changed or not by using following command
#object.column_changed? #=> true
You can get an array of changed attributes by using changed method
#object.changed #=> ['column_name']
You can try something like the following:
object.attribute_name_will_change!
object.changed << :attribute_name
puts object.attribute_name_changed?
puts object.changed?
resulting output is:
true
true
attribute_name is to be replaced with the name of your attribute.

Rails 5 with mongoid .changed is always empty on update

In my controller, I have the *_params to permit attributes. No matter what, even when things are definitely changed, .changed is always blank. Is there a new Rails 5 way to detect changed attributes?
# case_params is the basic rails controller permission method
if #case.update(case_params)
puts #case.changed.count # this is is always 0
...
Can anyone see what I'm doing wrong? I need to know what's changed so I can selectively do some other work in a thread but only for changed attributes.
Thanks for any help.
You can use #cases.previous_changes which gives all the changes to the document in the form of a hash. The hash also consitis of updated_at attribute. You can do -1 to the above count to get all the changed attributes count excluding updated_at.
You can get the count by #cases.previous_changes.keys.count - 1
We need to subtract -1 for removing updated_at attribute changes.
If you want to detect changes in the assosiation you can use try using children_changed? for it.

Rails - Get old value in before_save

I'm trying to get the old value in the before_save by adding "_was" to my value but it doesn't seem to work.
Here is my code:
before_save :get_old_title
def get_old_title
puts "old value #{self.title_was} => #{self.title}"
end
Both "title_was" and "title" got the new title just been saved.
Is it possible to get the old value inside before_save ?
The reason for you getting the same value is most probably because you check the output when creating the record. The callback before_save is called on both create() and update() but on create() both title and title_was are assigned the same, initial value. So the answer is "yes, you can get the old value inside before_save" but you have to remember that it will be different than the current value only if the record was actually changed. This means that the results you are getting are correct, because the change in question doesn't happen when the record is created.
Instead of before_save use before_update. It should work now.
So, the answer above might work but what if I wanted to get the previous value for some reason and use it to perform some task then you would need to get the previous value. In my case I used this
after_update do
if self.quantity_changed?
sku.decrement(:remaining, (self.quantity_was - self.quantity) * sku.quantity)
end
end
The _was and _changed? added to any of the columns would do the job to get the job done.
In rails 5.1.1 ActiveRecord::AttributeMethods::Dirty provides
saved_changes()
Link for saved_changes()
which returns a hash containing all the changes that were just saved.

Save one attribute for a row in active record

There are like 5 ways to save a new value for an attribute in ActiveRecord. Unfortunately I could only get one way to work and I am not sure it is the most efficient way:
review = Review.find(id)
review.status = 'ok'
review.save!
I started with the update method, but for some strange reason that deleted my review row
review = Review.update(id, :status => 'ok)
review.save!
Any ideas?
You should use
review = Review.find_by_id(id)
review.update_column(:status, 'ok')
has you can see the docs.
Note: ActiveRecord::Base:update has been deprecated in Rails 3.2.8
The most efficient way to save a new value for an attribute is to simply do:
Review.update_attribute(id, :status => 'ok')
There is no need to call the save method after this because ActiveRecord automatically saves the value with the update_attribute method.
Now, keep in mind that this will only work if the change will only work if it passes the validations set on the object.
Check out this link for more info:
http://apidock.com/rails/ActiveRecord/Base/update/class
It should be
review.update_attributes(status: 'ok')

Resources