Tuesday, 28 July 2009

Rails audit trail

I know I've just done another post but I wanted to also mention something to you I discovered yesterday for Ruby on Rails that is, frankly, excellent.

Many applications need to keep a history of things that have happened and those responsible for auditing purposes. In fact, this is very often a legal requirement. For anyone that's worked on an application where this is the case, you'll know all too well that every "Solution Architect" out there has their own favourite way of doing it, that it can be a headache to implement, and that it often arrives as a bit of an afterthought ("Ummm... shouldn't we be auditing this stuff?").



My preferred way of doing it (I told you we all had our own favourites) is to have a single database table that records all inserts, updates, and deletes. You have a couple of columns to specify the type of entity being affected and its primary key, and then a couple of columns indicating the specific attribute and its new value. Of course, you then get all the timestamp and user information in there too.

This is as opposed to the other oft-used mechanism of having a duplicate history table for each real table that keeps a record of all changes, which essentially means double the number of tables.

There are a whole variety of reasons why I prefer the single table approach, including:

  • I find it far easier to manage the auditing centrally;

  • Changes to real tables don't require corresponding changes to the audit table, although it will require an additional bit of SQL in your TRIGGER (if that's what you use) to account for those changes, which is minimal;

  • It's easier to see exactly what was changed - you don't have to compare rows in the history table to see which columns are different;

  • And... I could go on, but I'll stop there.



There will be plenty of you who will have a variety of reasons why you prefer another approach over that one, but that's not really what this post is about - though feel free to show me the error of my ways with a comment.

We've been working on a new project for a wee while now - a Rails one - and yesterday I decided to put the auditing in place before we got too far down the track of extending what was essentially a spike when I first put it together. To my astonishment, I found that Rails basically takes care of all the auditing for you - and just the way I like it - with a simple plugin.

There's very little change required to your code. It's just an "acts_as_audited" declaration at the top of each model you want to audit, with the ability to specify any attributes you specifically don't want to audit (e.g., passwords, credit card numbers, etc.), or you can put a simple "audit User, Product, Order" declaration in the ApplicationController and you're away.

How do I get my hands on this wonderful plugin?, I hear you ask. Well, you could get yourself over to to http://opensoul.org/2006/07/21/acts_as_audited and read some more about it and then follow the installation instructions on there or if, like me, you don't have a git client, you could do the following:

1. Fire up your command prompt/shell and run:
[shell gutter="false"]script/plugin install http://source.collectiveidea.com/public/rails/plugins/acts_as_audited[/shell]
Note: you may need to stick a "rails" at the front of that, depending on how you have it configured on your machine
2. Generate the migration script:
[shell gutter="false"]script/generate audited_migration add_audits_table[/shell]
3. Migrate it:
[shell gutter="false"]rake db:migrate[/shell]
4. Make the changes to your models:
[ror]class ApplicationController < ActionController::Base
audit User, Product, Order
end[/ror]
or
[ror]class User < ActiveRecord::Base
acts_as_audited :except => [ :password ]
# The rest of your model
end[/ror]

And that's it. Job done. 4 easy steps to auditing - and all you really had to decide was what you wanted to audit.

No comments:

Post a Comment