Keeping track of who did what and when is a common problem in any significant Web application. A canonical instance is found in wikis, where every piece of content is editable. Wiki software records all activity to provide for review and oversight and to provide recourse should errors be introduced in the system. (Indeed, that very auditing of additions and revisions encourages contribution.) However, auditing is just as important (or more so) in traditional editorial workflows, and no less essential in inventory management, where modifications can affect financial performance. Ultimately, any system, whether it has one user or one thousand users, can benefit from auditing. After all, humans make clerical errors, introduce bugs in code, and invent Ponzi schemes.
In general, coders should audit transactions whenever possible. While a regular backup plan hedges against data loss, audits safeguard against information loss. It’s fairly easy to cook up a solution—say, hook the CRUD functions in your application—but if you’re a Rails developer, there are a good number of capable gems and plug-ins ready for use. Ryan Bates looked at vestal versions in a recent Railscast, and acts_as_versioned has been available for quite some time. Here, I want to look at another impressive solution called, aptly, Paper Trail.
Paper Trail, as its name implies, creates a running record of changes in each ActiveRecord models you augment. Moreover, if you provide a current_user method in your ApplicationController, Paper Trail also journals who made each change. You can enumerate all the modifications made to a model, revert to a prior revision of a model, and even undelete a model. Smartly, Paper Trail can also be enabled and disabled programatically during migrations. Better yet, all these features are inherited with one addition to your code:
class Widget < ActiveRecord::Base
Installing Paper Trail
Let’s install Paper Trail and see how it works.
Paper Trail is available as both a plug-in and a gem. Let’s use the latter form so all Rails applications can benefit. To begin, create a new Rails application, edit the file config/environment.rb, and add a new config.gem entry to reflect the dependency on the Paper Trial gem.
$ cd /tmp
$ rails myapp
$ cd myapp
$ vi config/environment.rb
RAILS_GEM_VERSION = '2.3.4' unless defined? RAILS_GEM_VERSION
require File.join(File.dirname(__FILE__), 'boot')
Rails::Initializer.run do |config|
config.gem 'airblade-paper_trail', :lib => 'paper_trail', :source => 'http://gems.github.com'
After you edit the file, install the gem via rake.
$ sudo rake gems:install
gem install airblade-paper_trail --source http://gems.github.com
Successfully installed airblade-paper_trail-1.1.1
1 gem installed
Installing ri documentation for airblade-paper_trail-1.1.1...
Installing RDoc documentation for airblade-paper_trail-1.1.1...
Paper Trail maintains model versions its own set of tables, so the next is to create a suitable migration file and alter the database.
At this point, you are ready to go. Don’t forget to add has_paper_trial to models you want to audit.
Let’s see how Paper Trial works. To jumpstart the new, empty application, use a scaffold to create a new model, view, controller and migration. Call the new class a Gadget and assign it a handful of fields.
has_paper_trail adds a one-to-many relationship between a model and its versions. Hence, Gadget.find(1).versions yields an array of revisions.
Each revision stores the state of the object before a change was applied; the current state of an object is simply the model itself.
Thus, Gadget.find(1).versions[-1], always refers to the previous revision of the model with ID 1. The first version, ….versions.first, is special: it records the creation of the model. Its prior version is nil, since the model is newly created.
Paper Trail uses the field object to record a version of a model in JSON-like format. To convert from that internal representation back to ActiveRecord, use the method reify.
By design, Paper Trail does not store a duplicate of the current object, just the most penultimate revision. So, when you restore an object that’s been deleted, it returns to the state before it was destroyed. This makes some sense, too. If the current object was errant and was deleted as a result, you want to restore to the previous good state.
Not Just for Bean Counters
An audit trail, as Paper Trail produces, is invaluable. I did not show its use here, but Paper Trail records who made each change, too,in the whodunnit field. Given the who and what, you can deduce most any problem and have evidence of the change. You should consider vestal versions and other audit packages, too. The former lets you rollback to a specific revision and to a specific date. Very cool.
Fatal error: Call to undefined function aa_author_bios() in /opt/apache/dms/b2b/linux-mag.com/site/www/htdocs/wp-content/themes/linuxmag/single.php on line 62