Recipe 14.3. Manipulating Record Versions with acts_as_versioned


Problem

You want to let users view or revert versioned changes made to the rows in your database.

Solution

Use the acts_as_versioned plug-in to track changes made to rows in a table and to set up a view that allows access to the a revision history.

Start by installing the plug-in within your application:

$ ./script/plugin install acts_as_versioned             

Set up a database to store statements and to track changes made each statement. For versioning to work, the table being tracked needs to have a version column of type :int.

db/migrate/001_create_statements.rb:

class CreateStatements < ActiveRecord::Migration   def self.up     create_table 'statements' do |t|       t.column 'title', :string       t.column 'body', :text       t.column 'version', :int     end   end   def self.down     drop_table 'statements'   end end

Now, create a second table named statement_versions. The name of this table is based on the singular form of the name of the table being versioned, followed by the string _versions. This table accumulates all versions of the columns you want to track. Specify those columns by adding columns to the statement_versions table, each having the same name and datatype as the columns in the table you're tracking. The statement_versions table needs to have a version column of type :int as well. Next, add a column referencing the versioned table's id field, e.g., statement_id.

db/migrate/002_add_versions.rb:

class AddVersions < ActiveRecord::Migration   def self.up     create_table 'statement_versions' do |t|       t.column 'statement_id', :int       t.column 'title', :string       t.column 'body', :text       t.column 'version', :int     end   end   def self.down     drop_table 'statement_versions'   end end

Finally, set up the Statement model to be versioned by calling acts_as_versioned in its class definition:

app/models/statement.rb:

class Statement < ActiveRecord::Base   acts_as_versioned end

Now, changes made to Statement objects automatically update the object's version number and save current and previous versions in the statement_versions table. Being versioned, Statement objects gain a number of methods that allow for inspection and manipulation of versions. To allow users to revert versions, you can modify your Statements controller, adding a revert_version action:

def revert_version   @statement = Statement.find(params[:id])   @statement.revert_to!(params[:version])    redirect_to :action => 'edit', :id => @statement end

Modify the Statement edit view, adding linked version numbers that revert changes by calling the revert_version action.

app/views/edit.rhtml:

<h1>Editing statement</h1> <% form_tag :action => 'update', :id => @statement do %>   <%= render :partial => 'form' %>   <p><label for="statement_version">Version</label>:    <% if @statement.version > 0 %>     <% (1..@statement.versions.length).each do |v| %>       <% if @statement.version == v %>               <%= v %>       <% else %>         <%= link_to v, :action => 'revert_version', :id => @statement, \                                                     :version => v %>       <% end %>     <% end %>   <% end %>   </p>   <%= submit_tag 'Edit' %> <% end %> <%= link_to 'Show', :action => 'show', :id => @statement %> | <%= link_to 'Back', :action => 'list' %>

Discussion

You can use the Rails console to test a basic update and reversion session on a Statement object:

>> statement = Statement.create(:title => 'Invasion', :body => 'because of WMDs') => #<Statement:0x22f0c94 @attributes={"body"=>"because of WMDs",  "title"=>"Invasion", "id"=>6, "version"=>1}, @new_record=false,  @changed_attributes=[], @new_record_before_save=true,  @errors=#<ActiveRecord::Errors:0x22ef1b4 @base=#<Statement:0x22f0c94 ...>,  @errors={}>> >> statement.version => 1 >> statement.body = 'opp! no WMDs' => "opp! no WMDs" >> statement.save => true >> statement.version => 2 >> statement.revert_to!(statement.version-1) => true >> statement.body => "because of WMDs" >> statement.version => 1

Figure 14-1 shows the statement edit page. It includes links to all previous versions that call the revert action. Submitting the form using the edit button will add a new version number.

Figure 14-1. An edit form that displays links to previous versions


You can alter the default behavior by passing an option hash to the acts_as_versioned method. For example, :class_name and :table_name can be set if the default naming convention isn't suitable for your project. Another useful option is :limit, which specifies a fixed number of revisions to keep available.

See Also

  • The acts_as_versioned plug-in project page, at http://ar-versioned.rubyforge.org




Rails Cookbook
Rails Cookbook (Cookbooks (OReilly))
ISBN: 0596527314
EAN: 2147483647
Year: 2007
Pages: 250
Authors: Rob Orsini

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net