Logging Changes when Saving ActiveRecord Objects
Turns out that it’s pretty easy. Here’s my save_after_edit action:
# Save away an order after editing
def save_after_edit
if request.post?
@order = Order.find(params[:id])
changes = detect_changes(@order.attributes, params[:order])
if @order.update_attributes(params[:order])
log_changes(changes)
redirect_to(:action => :show_order, :id => @order)
end
end
end
The detect_changes method simply compares the attribute values that come back from the form with those in the object just read from the database.
def detect_changes(from, to)
result = []
to.each do |key, val|
if val != from[key]
label = Order.human_attribute_name(key)
result << "#{label}: '#{from[key]}' => '#{val}'"
end
end
result
end
The log_changes method writes the timestamped change details out to an audit table.
For my needs, doing this in the controller is good enough. However, it’d be really easy to produce an ActiveRecord mixin that added something like a changed_attributes() method to AR objects. Doing so would make the capability totally transparent to the rest of the application.




I have a similar situation where I am keeping track of changes to an AR object by overriding the attribute= methods for the attributes I am interested in tracking. I then use an after_update callback to log the changes.
One of the attributes I am tracking is actually an association (:users) and I keep track of who is assigned or unassigned from the object.
This worked fine when I was using a HABTM association but now that I am moving to a has_many :through I can't call 'object.users <<' before object has been saved. I can work around this by not using the after_update :log_changes and instead call it after I assign users to the object but this seems pretty ugly.
Is there a better way to do this?
Posted by: Yonatan Feldman | August 06, 2007 at 04:49 PM