Simple ActiveRecord versioning

Recently I've had the need to version ActiveRecord models for which, in the past, I have used Rick Olson's plugin acts_as_versioned.

Rick is a plugin dynamo and I happily use a number of his plugins in my projects but, for various reasons, I could never quite get on with acts_as_versioned. Perhaps it's because I struggled to follow the code in places or that I didn't like having an extra table and model for each model being versioned. Anyway it's not that acts_as_versioned doesn't work, I just wanted something simpler and more lightweight.

What I've ended up with is a plugin I've called SimplyVersioned. SimplyVersioned uses a single model and table to store version information from any number of application models using a polymorphic has_many relationship. Model attributes are stored in YAML format in a SQL text field.

My rationale is that access to version information won't be required often so the cost of pulling it out of a YAML hash is reasonable. There is the extra cost of converting to YAML on each save. Will that be an issue? If it is then perhaps Marshall#dump is an option. Time will tell I guess.

In use the interface is quite simple. To specify a model be versioned:

class Thing < ActiveRecord::Base
  simply_versioned :keep => 10

and from then on calls to create or save will automatically add versions. When there are more versions than you want to keep old versions are automatically destroyed.

To query versions:

thing.versions.each do |version| ... end
render :partial => 'thing_version', :collection => thing.versions

Revert changes:

thing.revert_to_version( 6, :except => [:name,:age] )

And if you don't want a version created when you save:

thing.without_versioning { }

The plugin includes a migration generator to create the versions table and requires no other modifications to your database or model classes. Install with:

./script/plugin install

To get this plugin working right I invested some time in getting the unit tests working right and, hopefully, I've done a reasonable job with it. If not please let me know about it. In particular I couldn't figure out how to get rcov to generate coverage for the plugin so there may be dark corners still to be illuminated.

30/12/2007 20:55 by Matt Mower | Permalink | comments:
More about: