If you need to add basic wiki style functionality to your Ruby on Rails models, there is a really easy way to get similar model versioning without having to resort to cutting the code yourself.
The acts_as_versioned ‘plugin’ has been available for quite some time, but its been made far better by it now becoming a gem instead of an old-school plugin. The authors have gone to considerable effort to make it as painless as possible to use.
This post, is designed to give you a brief over-view into how to get up and running with with models which ‘acts_as_versioned’. Because its the current version (at time of posting) and because its awesome, this walk-though assumes that you are using Rails 3, not 2. The instructions for Rails 2 sites are similar, but you’ll need to tweak this for it to work.
First, you need to grab the gem:
sudo gem install acts_as_versioned
Next, add the dependency to the ‘Gemfile’, it doesn’t matter too much where it goes, I stuck it somewhere in the middle:
gem 'acts_as_versioned', '0.6.0'
Next, just under the ‘ActiveRecord::Base’ line in the model’s class file, instruct the class that its to act as a versioned model.
class Article < ActiveRecord::Base
acts_as_versioned
end
Then, in the migration file you need to execute the model's method to create the version table. This is key because the acts_as_versioned gem actually creates an additional database table to house all the previous versions of a given record. Obviously, you need to delete the table is the schema is taken down. My migration now looks like:
class CreateArticles < ActiveRecord::Migration
def self.up
create_table :article do |t|
t.string :title
t.string :body
t.integer :user_id
t.timestamps
end
Article.create_versioned_table
end
def self.down
drop_table :articles
Article.drop_versioned_table
end
end
The key method is the
Article.create_versioned_table
which creates the version table of the model. Now, get rake to create the database:
rake db:migrate
Thats it! Its done. Using acts_as_versioned is simple. I'll provide some examples, where '@article' represents an instance of a model setup 'acts_as_versioned'. To find the current version of an article you can use the version property:
@article.version
But just performing a normal ActiveRecord lookup returns the most current version anyway, so to revert to a previous version use the revert_to method on an article instance:
@article.revert_to(version_number)
You can save (just like you've done a hundred times before) a previous version as the current on by using the save method. The save on a reverted articles will just create a new version.
To get the number of versions:
@article.versions.size
Since '@article.versions' returns an array of versions, you can do neat things like this:
History
<% for version in @article.versions.reverse %>
Version <%= version.version %>
<%= link_to '(revert to this version)',
:action => 'revert_to_version',
:version => version.id,
:id => @article %>
<% end %>
Obviously for this to work, you'd need to create a 'revert_to_version' action in the appropriate controller, but you get the idea.
acts_as_versioned is an amazing piece of work, and aside from the wiki-like functionality it gives you for very little effort, I can imagine scenarios such as audit and trace logs and "undo" features which could really benefit from this little gem.