I have an ActiveRecord model with a status column. When the model is saved with a status change I need to write to a history file the change of status and who was responsible for the change. I was thinking an after_save callback would work great, but I can't use the status_changed? dynamic method to determine that the history write is necessary to execute. I don't want to write to the history if the model is saved but the status wasn't changed. My only thought on handling it right now is to use an instance variable flag to determine if the after_save should execute. Any ideas?
4 Answers
This may have changed since the question was posted, but the after_save callback should have the *_changed?
dynamic methods available and set correctly:
class Order
after_save :handle_status_changed, :if => :status_changed?
end
or
class Order
after_save :handle_status_changed
def handle_status_changed
return unless status_changed?
...
end
end
Works correctly for me w/ Rails 2.3.2.

- 6,808
- 3
- 31
- 31
Use a before_save
callback instead. Then you have access to both the new and old status values. Callbacks are wrapped in a transaction, so if the save fails or is canceled by another callback, the history write will be rolled back as well.

- 2,757
- 2
- 20
- 18
-
`before_save` does not allow to create records (into a history table) – Maayan Naveh Mar 19 '20 at 12:45
I see two solutions:
Like you said: add a variable flag and run callback when it is set.
Run save_history after updating your record.
Example:
old_status = @record.status
if @record.update\_attributes(params[:record])
save_history_here if old_status != @record.status
flash[:notice] = "Successful!"
...
else
...
end

- 14,837
- 7
- 47
- 59
Has anyone not heard of database triggers? If you write an on_update database trigger on the database server, then every time a record gets updated, it will create a historical copy of the previous record's values in the associated audit table.
This is one of the main things I despise about Rails. It spends so much time trying to do everything for the developer that it fools developers into thinking that they have to follow such vulgar courses of action as writing specialized rails methods to do what the freaking database server already is fully capable of doing all by itself.
shakes head at Rails once again

- 2,866
- 9
- 31
- 37
-
If you can show me how to make a database trigger write to a history log file, I'll upvote you. – Georges May 23 '12 at 17:02
-
Why would a database trigger ever write to a log file? A trigger's sole purpose, in this instance, serves as a historical activity log on the table the trigger was written for. Logging to a file is an application's responsibility. I'm beginning to think that there is a fundamental lack of basic system comprehension. But, we are talking about Rails. So, I guess that explains the "do everything without knowing why" mentality. No offense, Georges. But Rails is a perversion of common sense programming at it's best. – Skittles May 27 '12 at 15:49
-
Ah, sorry. I guess I originally misread your comment as the original comment mentioned a history *file*. You're right. An audit table and triggers is much better in this instance. Upvoted. – Georges Jun 06 '12 at 03:32
-
1Without understanding the application and its requirements, you can't just dismiss techniques and frameworks. Just as a completely hypothetical example, imagine that the some audit records need to be created in the database and some need to be sent via a REST API to a remote audit server, depending on some info in the row. In that case a database trigger is completely inappropriate. I could come up with many situations where having rows generated by the database instead of the code is inappropriate. The only "perversion of common sense" is making blanket statements with no supporting data. – MikeJ Jul 05 '13 at 14:28