module VestalVersions # Adds the functionality necessary to control version creation on a versioned instance of # ActiveRecord::Base. module Creation def self.included(base) # :nodoc: base.class_eval do extend ClassMethods include InstanceMethods after_update :create_version, :if => :create_version? after_update :update_version, :if => :update_version? class << self alias_method_chain :prepare_versioned_options, :creation end end end # Class methods added to ActiveRecord::Base to facilitate the creation of new versions. module ClassMethods # Overrides the basal +prepare_versioned_options+ method defined in VestalVersions::Options # to extract the :only and :except options into +vestal_versions_options+. def prepare_versioned_options_with_creation(options) result = prepare_versioned_options_without_creation(options) self.vestal_versions_options[:only] = Array(options.delete(:only)).map(&:to_s).uniq if options[:only] self.vestal_versions_options[:except] = Array(options.delete(:except)).map(&:to_s).uniq if options[:except] result end end # Instance methods that determine whether to save a version and actually perform the save. module InstanceMethods private # Returns whether a new version should be created upon updating the parent record. def create_version? version_changes.present? end # Creates a new version upon updating the parent record. def create_version versions.create(version_attributes) reset_version_changes reset_version end # Returns whether the last version should be updated upon updating the parent record. # This method is overridden in VestalVersions::Control to account for a control block that # merges changes onto the previous version. def update_version? false end # Updates the last version's changes by appending the current version changes. def update_version return create_version unless v = versions.last v.changes_will_change! v.update_attribute(:changes, v.changes.append_changes(version_changes)) reset_version_changes reset_version end # Returns an array of column names that should be included in the changes of created # versions. If vestal_versions_options[:only] is specified, only those columns # will be versioned. Otherwise, if vestal_versions_options[:except] is specified, # all columns will be versioned other than those specified. Without either option, the # default is to version all columns. At any rate, the four "automagic" timestamp columns # maintained by Rails are never versioned. def versioned_columns case when vestal_versions_options[:only] then self.class.column_names & vestal_versions_options[:only] when vestal_versions_options[:except] then self.class.column_names - vestal_versions_options[:except] else self.class.column_names end - %w(created_at created_on updated_at updated_on) end # Specifies the attributes used during version creation. This is separated into its own # method so that it can be overridden by the VestalVersions::Users feature. def version_attributes {:changes => version_changes, :number => last_version + 1} end end end end