Audit Trail
At many cases, we have a use case called “Please keep all changes as history, showing who had created, or updated such record and log the time s/he did that” — This is a typical audit trail task in a very common system.

“Tommy created Products at 2008-08-20″ and “Thomas updated Orders at 2008-08-30 with Price set to $100″
In rails, we have many cool plugins for doing this features. Some would log all the version you made to that particular model, or have the feature that you can revert the version back. In the current project, we simply need an audit statement but not the revision feature. No need to rollback….it is too fancy.

acts_as_audited

Act as versioned: http://wiki.rubyonrails.org/rails/pages/ActsAsVersioned

Act as audited: http://opensoul.org/2006/7/21/acts_as_audited

We have compared act as versioned and act as audited and finally made some hacks on the act as audited plugin.

As we use RESTful_authenticated for our customer model and administrator model, the plugin automatically draw the user_type to Administrator or User, while the username field is left out. We have done some hack to the plugin to log the ip address when the user is not logged in and store the ip into the field username.

Here is the hack:
in lib/acts_as_audited.rb, pass also the ip address to the username field

def audit_create(user = nil, ip = nil)
write_audit(:action => 'create', :changes => audited_attributes, :user => user, :username => ip)
end
def audit_update(user = nil, ip = nil)
unless (changes = changed_audited_attributes).empty?
write_audit(:action => 'update', :changes => changes, :user => user, :username => ip)
end
end
def audit_destroy(user = nil, ip = nil)
write_audit(:action => 'destroy', :user => user, :username => ip)
end

in audit_sweeper.rb, retrieve the ip address from the request

def after_create(record)
# username field is HACKed to store the ip address
ip = request.remote_ip rescue ip = 'Unknown'
record.send(:audit_create, current_user, ip)
end
def after_destroy(record)
ip = request.remote_ip rescue ip = 'Unknown'
record.send(:audit_destroy, current_user, ip)
end
def before_update(record)
ip = request.remote_ip rescue ip = 'Unknown'
record.send(:audit_update, current_user, ip)
end

In addition, a namescope is added to the audit.rb to retrieve a particular admin’s history on particular model:

# name scope for retrieving a particular admin's history on particular model
named_scope :history, lambda {|model,admin| {:conditions => ['user_type = ? and user_id = ? and auditable_type = ? ', 'Administrator' , admin, model]}}