Vestal Versions

Gem Version Build Status Code Climate Coverage Status Dependency
Status

Finally, DRY ActiveRecord versioning!

acts_as_versioned[http://github.com/technoweenie/acts_as_versioned] by technoweenie was a great start, but it failed to keep up with ActiveRecord's introduction of dirty objects in version 2.1. Additionally, each versioned model needs its own versions table that duplicates most of the original table's columns. The versions table is then populated with records that often duplicate most of the original record's attributes. All in all, not very DRY.

vestal_versions[http://github.com/laserlemon/vestal_versions] requires only one versions table (polymorphically associated with its parent models) and no changes whatsoever to existing tables. But it goes one step DRYer by storing a serialized hash of only the models' changes. Think modern version control systems. By traversing the record of changes, the models can be reverted to any point in time.

And that's just what vestal_versions does. Not only can a model be reverted to a previous version number but also to a date or time!

Compatibility

Tested with Active Record 3.2.16 with Ruby 1.9.3 and 1.9.2.

Installation

In the Gemfile:

** Note: I am giving this project some much needed love to keep her relevant in a post Rails 3 world. I will be finalizing a version to support 1.9.2+ and Rails 3.2+ soon and pushing the gem, till then, use the git repo: ~dreamr

gem 'vestal_versions', :git => 'git://github.com/laserlemon/vestal_versions'

Next, generate and run the first and last versioning migration you'll ever need:

$ rails generate vestal_versions:migration
$ rake db:migrate

Example

To version an ActiveRecord model, simply add versioned to your class like so:

class User < ActiveRecord::Base
  versioned

  validates_presence_of :first_name, :last_name

  def name
    "#{first_name} #{last_name}"
  end
end

It's that easy! Now watch it in action…

>> u = User.create(:first_name => "Steve", :last_name => "Richert")
=> #<User first_name: "Steve", last_name: "Richert">
>> u.version
=> 1
>> u.update_attribute(:first_name, "Stephen")
=> true
>> u.name
=> "Stephen Richert"
>> u.version
=> 2
>> u.revert_to(10.seconds.ago)
=> 1
>> u.name
=> "Steve Richert"
>> u.version
=> 1
>> u.save
=> true
>> u.version
=> 3
>> u.update_attribute(:last_name, "Jobs")
=> true
>> u.name
=> "Steve Jobs"
>> u.version
=> 4
>> u.revert_to!(2)
=> true
>> u.name
=> "Stephen Richert"
>> u.version
=> 5

Upgrading to 1.0

For the most part, version 1.0 of vestal_versions is backwards compatible, with just a few notable changes:

New to 1.0

There are a handful of exciting new additions in version 1.0 of vestal_versions. A lot has changed in the code: much better documentation, more modular organization of features, and a more exhaustive test suite. But there are also a number of new features that are available in this release of vestal_versions:

Thanks!

Thank you to all those who post issues and suggestions. And special thanks to:

To contribute to vestal_versions, please fork, hack away in the integration branch and send me a pull request. Remember your tests!