Browse the Ruby on Rails Community.

You are here: Browse Railsplugins Acts As Diff

Acts As Diff

= acts_as_diff

Suppose you have a database table that you don’t want to change (e.g. you bought an expensive database), but you still want to store modifications to that table. Then acts_as_diff is for you!

Let’s say you bought a database containing all songs of all times. There are the tables “artist”, “albums” and “songs”, with the corrensponding models “Artist”, “Album” and Song>

create_table :artists do |t| t.column :first_name, :string t.column :last_name, :string t.column :birthday, :date end

create_table :albums do |t| t.column :artist_id, :integer t.column :name, :strong end

create_table :songs do |t| t.column :album_id, :integer t.column :name, :string t.column :duration, :time end

class Artist < ActiveRecord::Base has_many :albums end

class Album < ActiveRecord::Base belongs_to :artist has_many :songs end

class Song < ActiveRecord::Base belongs_to :album end

You would like to keep your own modifications in different tables, but you want that transparently to your application. For each of the tables, create a diff-table with the same columns as the original tables except a) leave out the foreign keys and b) reference the original table in the diff table:

create_table :artist_diffs do |t| t.column :artist_id, :integer t.column :first_name, :string t.column :last_name, :string t.column :birthday, :date end

create_table :album_diffs do |t| t.column :album_id, :integer t.column :name, :strong end

create_table :song_diffs do |t| t.column :song_id, :integer t.column :name, :string t.column :duration, :time end

Now the interesting part: The models for the diff tables reference the models for the original tables with the “is_diff” statement:

class ArtistDiff < ActiveRecord::Base is_diff :to => :artist end

class AlbumDiff < ActiveRecord::Base is_diff :to => :album end

class SongDiff < ActiveRecord::Base is_diff :to => :song end

Also, the models for the original tables need to know about the diff tables:

class Artist < ActiveRecord::Base # ... has_diff :in => :artist_diff end

class Album < ActiveRecord::Base # ... has_diff :in => :album_diff end

class Song < ActiveRecord::Base # ... has_diff :in => :song_diff end

Now, every change that you save to the Artist, Album or Song models will be saved in the diff tables. Let’s try it:

jimi = Artist.find(:first) => #<artist:0×32ff078>”Jimi”, “last_name”=>”Hendrix”, “id”=>”1”, “birthday”=>”1942-11-27”}>

jimi.update_attributes(:first_name => “James Marshall”) => #<artist:0×32ff078>”Jimi”, “last_name”=>”Hendrix”, “id”=>”1”, “birthday”=>”1942-11-27”}>

Note that the first name did not change. But, when accessed directly, you get:

jimi.first_name => “James Marshall”

This value was saved in the diff table, which can be accessed through the “diff” method:

jimi.diff => #<artistdiff:0×32ff082>”1”, “first_name”=>”James Marshall”, “last_name”=>nil, “id”=>”1”, “birthday”=>nil}>

Note that the diff table contains only the values for the changed columns. If you want to rollback the changes you have made, simply destroy the record in the diff table, or set the column to nil:

jimi.diff.destroy => #<artistdiff:0×32ff082>”1”, “first_name”=>”James Marshall”, “last_name”=>nil, “id”=>”1”, “birthday”=>nil}>

jimi.first_name => “Jimi”

Now, the first name is the original again.

Installation

We don't have a public SVN server yet, so you have to unpack this plugin to vendor/plugins inside your rails project.

Usage

Plugin usage in short (for the longer explanation, see above):

- For each table that you don’t want to modify directly, create a diff table (e.g. for artists, create artist_diffs) - In the model for the original table, add the has_diff statement (e.g. has_diff :in => :artist_diff) - In the model for the diff table, add the is_diff statement (e.g. is_diff :to => :artist)

To disable the plugin temporarily, use the class method disable_diff_table. This is useful, if you want to update the original table. Call the class method enable_diff_table after you’re done.

Status

This plugin is in a very early state and has not yet been used in a production environment, i.e. there are bugs. Feel free to fix them and to send patches :-)

TODO

- Methods to explicitly access the original or the modified data - Method to clear all or selected modifications for a given record - Possibility to explicitly set a column to nil in the diff table (right now, nil in the diff table means “no change”) - Performance improvements for large queries (possibly using :include) - Documentation - Tests

License

Released under the MIT license.

Authors
  • Thomas Kadauke (tkadauke@imedo.de)

NOTE: This description has been extracted from the Plugin README and so the formatting may need updating to make browser friendly

Users


See all details


Membership

+ Join this railsplugin

Record Maintainer

'None'