Using ActiveRecord, there is a way to get old record values ​​during after_update

Setting up using a simple example: I have 1 table ( Totals ), which contains the sum of the amount column of each record in the second table ( Things ).

When thing.amount updated, I would just add the difference between the old value and the new value in total.sum .

Now I subtract self.amount during before_update and add self.amount during after_update . This causes WAY to trust the update too much.

Limitation: I do not want to simply recount the sum of all transactions.

Question: I just want to get the original value during the after_update . What were your ways of doing this?

Update: I will go with the idea of ​​Luke Frank. During the after_update , you still have access to the self.attr_was values, which are exactly what I wanted. I also decided to go with the after_update implementation, because I want to save such a model in the model. Thus, no matter how I decide to update transactions in the future, I will know that I am updating the transaction amount correctly. Thank you all for your implementation recommendations.

+60
callback ruby-on-rails activerecord model
Mar 03 '09 at 16:19
source share
8 answers

Same as everyone says about transactions.

That said ...

ActiveRecord with Rails 2.1 keeps track of object attribute values. So if you have a total attribute, will you have a total_changed? method total_changed? and the total_was method, which returns the old value.

There is no need to add anything to your model to no longer keep track of it.

Update: The following is the documentation for ActiveModel :: Dirty as requested.

+122
Mar 03 '09 at 16:33
source share

Some other people mention packaging all of this in a transaction, but I think this is done for you; you just need to trigger the rollback by throwing an exception for errors in the after_ * callbacks.

See http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

The whole save, save !, or destroy callback chain is triggered in the transaction. This includes after_ * hooks. If everything goes well, COMMIT is executed after the chain completes.

If the before_ * callback cancels the action, a ROLLBACK is returned. You can also run ROLLBACK by throwing an exception in any of the callbacks, including after_ * hooks. Please note, however, that in this case, the client should be aware of this, because regular saving will result in such an exception, instead of calmly returning false.

+8
Mar 03 '09 at 16:47
source share

To get all changed fields with old and new values ​​respectively:

 person = Person.create!(:name => 'Bill') person.name = 'Bob' person.save person.changes # => {"name" => ["Bill", "Bob"]} 
+6
Aug 05 '13 at 18:55
source share

Adding "_was" to your attribute will give you the previous value before saving the data.

These methods are called dirty methods .

Hurrah!

+5
Jul 02 '14 at 10:09
source share

ActiveRecord :: Dirty is a module built into ActiveRecord to track attribute changes. That way you can use thing.amount_was to get the old value.

+4
Mar 03 '09 at 17:08
source share

Add this to your model:

 def amount=(new_value) @old_amount = read_attribute(:amount) write_attribute(:amount,new_value) end 

Then use @old_amount in your after_update code.

+2
Mar 03 '09 at 16:32
source share

First, you must do this in a transaction to ensure that your data is collected.

To answer your question, you can simply set the member variable to the old value in the before_update file, which you can access in after_update, however this is not a very elegant solution.

0
Mar 03 '09 at 16:28
source share

Idea 1: wrap the update in a database transaction, so if the update does not complete, your Totals table will not be changed: ActiveRecord Transactions documents

Idea 2: put the old value in @old_total during before_update.

0
Mar 03 '09 at 16:28
source share



All Articles