An experimental feature by technoweenie (see link at bottom). Specify this act if you want to save a copy of the row in a versioned table. This assumes there is a versioned table ready and that your model has a version field. This works with optimisic locking if the lock_version column is present as well.
%{color:red}As of July 21, 2008: Be sure to download this from the Github repository, using ./script/plugin install git://github.com/technoweenie/acts_as_versioned.git
%
The model that you’re versioning needs to have a ‘version’ attribute. The model is versioned into a table called #{model}_versions where the model name is singular. The _versions table should contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
Acts_as_versioned comes prepared with the create_versioned_table method, perfect for a migration:
class AddPostsVersions < ActiveRecord::Migration
require_dependency 'post'
def self.up
# create_versioned_table takes the same options hash
# that create_table does
Post.create_versioned_table
end
def self.down
Post.drop_versioned_table
end
end
class Page < ActiveRecord::Base
# assumes page_versions table
acts_as_versioned
end
page = Page.create(:title => 'hello world!')
page.version # => 1
page.title = 'goodbye world'
page.save # doesn't this have to be saved before the version changes?
page.version # => 2
page.versions.size # => 2
page.revert_to(1) # using version number
page.title # => 'hello world!'
page.revert_to(page.versions.last) # using versioned instance
page.title # => 'goodbye world'
page.revert_to!(1) # reverts and saves the model's changes
Configuration options are:
acts_as_versioned :if => Proc.new { |auction| !auction.expired? } </pre>
or…
class Auction def version_condition_met? # totally bypasses the <tt>:if</tt> option !expired? end end </pre>
Provided as a Rails plugin. Install by first updating your plugin source list if necessary, then installing the plugin:
$ ruby script/plugin discover
$ ruby script/plugin install acts_as_versioned
Caveat Emptor: The above may install an out-of-date version that will break on Rails 2.1. The most current code is in the git repository below.
I had been using my own versioning system, keeping old versions in the same table as current versions in a sort of linked list. I managed to convert this to ActsAsVersioned using the following in a migration (very ugly):
# versions is an ordered array of all old versions, oldest first
# primary is the current version and is included in the versions array
# the tables and models have already been set to act as versioned
versions.each do |obsolete_rev|
# See ActsAsVersioned set_new_version; ignores locking?
primary.send("#{primary.class.version_column}=", (primary.versions.calculate(:max, :version) || 0) + 1)
primary.save_without_revision!
# See ActsAsVersioned save_version_on_create
rev = primary.class.versioned_class.new
primary.clone_versioned_model(obsolete_rev, rev)
rev.version = primary.send(primary.class.version_column)
rev.send("#{primary.class.versioned_foreign_key}=", primary.id)
rev.save
obsolete_rev.destroy unless obsolete_rev == primary
end
— Patrick
create_versioned_table can add version column to model’s table automatically if there is no column named version or lock_version. drop_versioned_table won’t remove this column from model.#{model}_versions table from the DB each time a #{model} object is saved. This affects the ActsAsVersioned plugin since versions are associated to the #{model}, and may get very large if updated frequently. See Rails ticket 6822. canadaduaneEjemplo de uso, en español
http://ljorquera.blogspot.com/2007/08/versionado-de-tablas-con-ruby-on-rails.html