Yesterday

The Yesterday gem lets you track changes made in ActiveRecord models. It’s also possible to diff different versions. The big difference with this gem and other is, is that it is possible to diff all child objects (has_many, belongs_to & has_and_belongs_to_many) and it’s changes.

Note: work in progress

In the meanwhile: www.youtube.com/watch?v=YgtByWlBSdA

Installation

Install the gem:

gem install yesterday

And then run the generator in your Rails 3 project:

rails generate yesterday:install

Use tracking in your models

class Contact < ActiveRecord::Base
  has_many :addresses
  track_changes
end

class Address < ActiveRecord::Base
  has_many :companies
  exclude_tracking_for :associations => :companies
end

Checking version number

some_contact = Contact.find(10)
some_contact.version_number

Viewing historical data of an object

Viewing a version from an already found active record model:

some_contact = Contact.find(10)
some_contact.version(2)

Or using in a scope chain:

Contact.where(:first_name => 'foo').last.version(3)

Both of the above examples will return a Yesterday::VersionedObject

contact = Contact.create :first_name => 'foo'
contact.update_attribute :first_name => 'baz'

puts contact.version(1).first_name # -> foo
puts contact.version(2).first_name # -> baz

Diffing two versions

Use version numbers two compare two versions:

contact = Contact.create :first_name => 'foo'
contact.update_attribute :first_name => 'baz'

diff = contact.diff_version(1, 2)
puts diff.first_name.current # -> baz
puts diff.first_name.previous # -> foo

Diff’s within associations:

address = [Address.new(:address => 'blah')]

contact = Contact.new :first_name => 'foo'
contact.addresses = [address]
contact.save!

contact.addresses.first.address = 'blahblah'
contact.save!

diff = contact.diff_version(1, 2)
puts diff.addresses.first.address.current # -> blahblah
puts diff.addresses.first.address.previous # -> foo

To check if associations are created, just use the created_ prefix before the appropiate association:

contact.addresses.first.created?

Or, for removed associations:

contact.addresses.first.destroyed?

Or, just modified:

contact.addresses.first.modified?

Or… nothing:

contact.addresses.first.unmodified?

License and credits

Use it and have fun with it! Comments, cakes and hugs are welcome! Just stick to the license!

Copyright 2011, Diederick Lawson - Altovista. Released under the FreeBSD license.