PaperTrail lets you track changes to your models' data. It's good for auditing or versioning. You can see how a model looked at any stage in its lifecycle, revert it to any version, and even undelete it after it's been destroyed.
- Stores every create, update and destroy.
- Does not store updates which don't change anything.
- Allows you to get at every version, including the original, even once destroyed.
- Allows you to get at every version even if the schema has since changed.
- Automatically records who was responsible if your controller has a
- Allows you to set who is responsible at model-level (useful for migrations).
- Can be turned off/on (useful for migrations).
- No configuration necessary.
- Stores everything in a single database table (generates migration for you).
- Thoroughly tested.
Known to work on Rails 2.3. Probably works on Rails 2.2 and 2.1.
PaperTrail is simple to use. Just add 15 characters to a model to get a paper trail of every
class Widget < ActiveRecord::Base has_paper_trail end
This gives you a
versions method which returns the paper trail of changes to your model.
>> widget = Widget.find 42 >> widget.versions # [<Version>, <Version>, ...]
Once you have a version, you can find out what happened:
>> v = widget.versions.last >> v.event # 'update' (or 'create' or 'destroy') >> v.whodunnit # '153' (if the update was via a controller and # the controller has a current_user method, # here returning the id of the current user) >> v.created_at # when the update occurred >> widget = v.reify # the widget as it was before the update; # would be nil for a create event
PaperTrail stores the pre-change version of the model, unlike some other auditing/versioning plugins, so you can retrieve the original version. This is useful when you start keeping a paper trail for models that already have records in the database.
>> widget = Widget.find 153 >> widget.name # 'Doobly' # Add has_paper_trail to Widget model. >> widget.versions #  >> widget.update_attributes :name => 'Wotsit' >> widget.versions.first.reify.name # 'Doobly' >> widget.versions.first.event # 'update'
This also means that PaperTrail does not waste space storing a version of the object as it currently stands. The
versions method gives you previous versions; to get the current one just call a finder on your
Widget model as usual.
Here's a helpful table showing what PaperTrail stores:
|Event||Model Before||Model After|
PaperTrail stores the values in the Model Before column. Most other auditing/versioning plugins store the After column.
Reverting And Undeleting A Model
PaperTrail makes reverting to a previous version easy:
>> widget = Widget.find 42 >> widget.update_attributes :name => 'Blah blah' # Time passes.... >> widget = widget.versions.last.reify # the widget as it was before the update >> widget.save # reverted
Undeleting is just as simple:
>> widget = Widget.find 42 >> widget.destroy # Time passes.... >> widget = Version.find(153).reify # the widget as it was before it was destroyed >> widget.save # the widget lives!
In fact you could use PaperTrail to implement an undo system, though I haven't had the opportunity yet to do it myself.
Finding Out Who Was Responsible For A Change
ApplicationController has a
current_user method, PaperTrail will store the value it returns in the
whodunnit column. Note that this column is a string so you will have to convert it to an integer if it's an id and you want to look up the user later on:
>> last_change = Widget.versions.last >> user_who_made_the_change = User.find last_change.whodunnit.to_i
In a migration or in
script/console you can set who is responsible like this:
>> PaperTrail.whodunnit = 'Andy Stewart' >> widget.update_attributes :name => 'Wibble' >> widget.versions.last.whodunnit # Andy Stewart
Turning PaperTrail Off/On
Sometimes you don't want to store changes. Perhaps you are only interested in changes made by your users and don't need to store changes you make yourself in, say, a migration.
If you are about change some widgets and you don't want a paper trail of your changes, you can turn PaperTrail off like this:
And on again like this:
Install PaperTrail either as a gem or as a plugin:
config.gem 'airblade-paper_trail', :lib => 'paper_trail', :source => 'http://gems.github.com'
script/plugin install git://github.com/airblade/paper_trail.git
Generate a migration which will add a
versionstable to your database.
Run the migration.
has_paper_trailto the models you want to track.
PaperTrail has a thorough suite of tests. However they only run when PaperTrail is sitting in a Rails app's
vendor/plugins directory. If anyone can tell me how to get them to run outside of a Rails app, I'd love to hear it.
Please use GitHub's issue tracker.
Copyright (c) 2009 Andy Stewart (firstname.lastname@example.org). Released under the MIT licence.