Brandon
Brandon

Reputation:

Rails after_save callback to create an associated model based on column_changed?

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?

Upvotes: 6

Views: 8945

Answers (4)

Skittles
Skittles

Reputation: 2918

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

Upvotes: -7

Jordan Brough
Jordan Brough

Reputation: 7195

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.

Upvotes: 11

Andrew Watt
Andrew Watt

Reputation: 2767

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.

Upvotes: 6

klew
klew

Reputation: 14977

I see two solutions:

  1. Like you said: add a variable flag and run callback when it is set.

  2. 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

Upvotes: 0

Related Questions