ProblemYou want to let users view or revert versioned changes made to the rows in your database. SolutionUse 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' %> DiscussionYou 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 versionsYou 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
|