Setup using a simple example: I've got 1 table (Totals
) that holds the sum of the amount
column of each record in a second table (Things
).
When a thing.amount
gets updated, I'd like to simply add the difference between the old value and the new value to total.sum
.
Right now I'm subtracting self.amount
during before_update
and adding self.amount
during after_update
. This places WAY too much trust in the update succeeding.
Constraint: I don't want to simply recalculate the sum of all the transactions.
Question: Quite simply, I'd like to access the original value during an after_update
callback. What ways have you come up with do this?
Update: I'm going with Luke Francl's idea. During an after_update
callback you still have access to the self.attr_was
values which is exactly what I wanted. I also decided to go with an after_update
implementation because I want to keep this kind of logic in the model. This way, no matter how I decide to update transactions in the future, I'll know that I'm updating the sum of the transactions correctly. Thanks to everyone for your implementation suggestions.
ActiveRecord::Dirty is a module that's built into ActiveRecord for tracking attribute changes. So you can use
thing.amount_was
to get the old value.Idea 1: Wrap the update in a database transaction, so that if the update fails your Totals table isn't changed: ActiveRecord Transactions docs
Idea 2: Stash the old value in @old_total during the before_update.
To get all changed fields, with their old and new values respectively:
Some other folks are mentioning wrapping all this in a transaction, but I think that's done for you; you just need to trigger the rollback by raising an exception for errors in the after_* callbacks.
See http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html
Add this to your model:
Then use @old_amount in your after_update code.
Firstly, you should be doing this in a transaction to ensure that your data gets written together.
To answer your question, you could just set a member variable to the old value in the before_update, which you can then access in the after_update, however this isn't a very elegant solution.