Module | ActiveRecord::Acts::Versioned::ClassMethods |
In: |
lib/acts_as_versioned.rb
|
find first version after the given version.
# File lib/acts_as_versioned.rb, line 237 def self.after(version) find :first, :order => 'version', :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version] end
find first version before the given version
# File lib/acts_as_versioned.rb, line 231 def self.before(version) find :first, :order => 'version desc', :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version] end
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
class Auction acts_as_versioned do def started? !started_at.nil? end end end
or…
module AuctionExtension def started? !started_at.nil? end end class Auction acts_as_versioned :extend => AuctionExtension end Example code: @auction = Auction.find(1) @auction.started? @auction.versions.first.started?
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
By default, acts_as_versioned will version all but these fields:
[self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
You can add or change those by modifying non_versioned_columns. Note that this takes strings and not symbols.
class Post < ActiveRecord::Base acts_as_versioned self.non_versioned_columns << 'comments_count' end
# File lib/acts_as_versioned.rb, line 166 def acts_as_versioned(options = {}, &extension) # don't allow multiple calls return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods) send :include, ActiveRecord::Acts::Versioned::ActMethods cattr_accessor :versioned_class_name, :versioned_foreign_key, :versioned_table_name, :versioned_inheritance_column, :version_column, :max_version_limit, :track_altered_attributes, :version_condition, :version_sequence_name, :non_versioned_columns, :version_association_options, :version_if_changed, :versions_name self.versioned_class_name = options[:class_name] || "Version" self.versioned_foreign_key = options[:foreign_key] || self.to_s.foreign_key self.versioned_table_name = options[:table_name] || "#{table_name_prefix}#{base_class.name.demodulize.underscore}_versions#{table_name_suffix}" self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}" self.version_column = options[:version_column] || 'version' self.version_sequence_name = options[:sequence_name] self.max_version_limit = options[:limit].to_i self.version_condition = options[:if] || true self.versions_name = options[:versions_name] || :versions self.non_versioned_columns = [self.primary_key, inheritance_column, self.version_column, 'lock_version', versioned_inheritance_column] + options[:non_versioned_columns].to_a.map(&:to_s) self.version_association_options = { :class_name => "#{self.to_s}::#{versioned_class_name}", :foreign_key => versioned_foreign_key, :dependent => :delete_all }.merge(options[:association_options] || {}) if block_given? extension_module_name = "#{versioned_class_name}Extension" silence_warnings do self.const_set(extension_module_name, Module.new(&extension)) end options[:extend] = self.const_get(extension_module_name) end class_eval "has_many :\#{versions_name.to_s}, version_association_options do\n# finds earliest version of this record\ndef earliest\n@earliest ||= find(:first, :order => '\#{version_column}')\nend\n\n# find latest version of this record\ndef latest\n@latest ||= find(:first, :order => '\#{version_column} desc')\nend\nend\nbefore_save :set_new_version\nafter_save :save_version\nafter_save :clear_old_versions\n\nunless options[:if_changed].nil?\nself.track_altered_attributes = true\noptions[:if_changed] = [options[:if_changed]] unless options[:if_changed].is_a?(Array)\nself.version_if_changed = options[:if_changed].map(&:to_s)\nend\n\ninclude options[:extend] if options[:extend].is_a?(Module)\n" # create the dynamic versioned model const_set(versioned_class_name, Class.new(ActiveRecord::Base)).class_eval do def self.reloadable? ; false ; end # find first version before the given version def self.before(version) find :first, :order => 'version desc', :conditions => ["#{original_class.versioned_foreign_key} = ? and version < ?", version.send(original_class.versioned_foreign_key), version.version] end # find first version after the given version. def self.after(version) find :first, :order => 'version', :conditions => ["#{original_class.versioned_foreign_key} = ? and version > ?", version.send(original_class.versioned_foreign_key), version.version] end def previous self.class.before(self) end def next self.class.after(self) end def versions_count page.version end end versioned_class.cattr_accessor :original_class versioned_class.original_class = self versioned_class.set_table_name versioned_table_name versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym, :class_name => "::#{self.to_s}", :foreign_key => versioned_foreign_key versioned_class.send :include, options[:extend] if options[:extend].is_a?(Module) versioned_class.set_sequence_name version_sequence_name if version_sequence_name end