| Module | ActiveRecord::Acts::Versioned::ClassMethods |
| In: |
lib/acts_as_versioned.rb
|
acts_as_versioned :if => Proc.new { |auction| !auction.expired? }
or…
class Auction
def version_condition_met? # totally bypasses the <tt>:if</tt> option
!expired?
end
end
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 singlular. The _versions table should contain all the fields you want versioned, the same version column, and a #{model}_id foreign key field.
A lock_version field is also accepted if your model uses Optimistic Locking. If your table uses Single Table inheritance, then that field is reflected in the versioned model as ‘versioned_type’ by default.
Acts_as_versioned comes prepared with the ActiveRecord::Acts::Versioned::ActMethods::ClassMethods#create_versioned_table method, perfect for a migration. It will also create the version column if the main model does not already have it.
class AddVersions < ActiveRecord::Migration
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
# File lib/acts_as_versioned.rb, line 107
107: def acts_as_versioned(options = {})
108: # don't allow multiple calls
109: return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)
110:
111: class_eval do
112: include ActiveRecord::Acts::Versioned::ActMethods
113: cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column,
114: :version_column, :max_version_limit, :track_changed_attributes, :version_condition, :version_sequence_name
115: attr_accessor :changed_attributes
116: end
117:
118: self.versioned_class_name = options[:class_name] || "#{self.to_s.demodulize}Version"
119: self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key
120: self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{Inflector.underscore(Inflector.demodulize(class_name_of_active_record_descendant(self)))}_versions#{table_name_suffix}"
121: self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
122: self.version_column = options[:version_column] || 'version'
123: self.version_sequence_name = options[:sequence_name]
124: self.max_version_limit = options[:limit].to_i
125: self.version_condition = options[:if] || true
126:
127: class_eval do
128: has_many :versions,
129: :class_name => "ActiveRecord::Acts::Versioned::#{versioned_class_name}",
130: :foreign_key => "#{versioned_foreign_key}",
131: :order => 'version'
132: before_save :set_new_version
133: after_create :save_version_on_create
134: after_update :save_version
135: after_save :clear_old_versions
136: after_save :clear_changed_attributes
137:
138: unless options[:if_changed].nil?
139: self.track_changed_attributes = true
140: options[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)
141: options[:if_changed].each do |attr_name|
142: define_method("#{attr_name}=") do |value|
143: (self.changed_attributes ||= []) << attr_name.to_s unless self.changed?(attr_name) or self.send(attr_name) == value
144: write_attribute(attr_name.to_s, value)
145: end
146: end
147: end
148: end
149:
150: # create the dynamic versioned model
151: # maybe if i sit down long enough i can think up a better way to do this.
152: dynamic_model = "class ActiveRecord::Acts::Versioned::\#{versioned_class_name} < ActiveRecord::Base\nset_table_name \"\#{versioned_table_name}\"\nbelongs_to :\#{self.to_s.demodulize.underscore}, :class_name => \"\#{self.to_s}\"\n"
153:
154: dynamic_model += %Q{set_sequence_name "#{version_sequence_name}"\n} if version_sequence_name
155:
156: eval dynamic_model + 'end'
157: end