From 9acc5ed6df7522682abc84a3d4886bb738cd11b3 Mon Sep 17 00:00:00 2001 From: Brian Durand Date: Mon, 21 Nov 2011 18:10:25 -0600 Subject: [PATCH] Add nicer syntax for simply copying attributes into revision metadata. --- lib/acts_as_revisionable.rb | 36 +++++++++++++++++++---------- spec/acts_as_revisionable_spec.rb | 38 ++++++++++++++++++++++++++++--- 2 files changed, 59 insertions(+), 15 deletions(-) diff --git a/lib/acts_as_revisionable.rb b/lib/acts_as_revisionable.rb index bb3b20f..375c603 100644 --- a/lib/acts_as_revisionable.rb +++ b/lib/acts_as_revisionable.rb @@ -5,10 +5,6 @@ module ActsAsRevisionable autoload :RevisionRecord, File.expand_path('../acts_as_revisionable/revision_record', __FILE__) - def self.included(base) - base.extend(ActsMethods) - end - module ActsMethods # Calling acts_as_revisionable will inject the revisionable behavior into the class. Specifying a :limit option # will limit the number of revisions that are kept per record. Specifying :minimum_age will ensure that revisions are @@ -39,6 +35,11 @@ module ActsMethods # :version => 1 # } # + # As a shortcut, you can can also just pass an attribute name or array of attribute names to copy to the revision + # record. + # + # acts_as_revisionable :meta => :updated_by + # # The values to the :meta hash can be either symbols or Procs. If it is a symbol, the method # so named will be called on the record being revisioned. If it is a Proc, it will be called with the # record as the argument. Any other class will be sent directly to the revision record. @@ -248,14 +249,14 @@ def create_revision! revision = revision_record_class.new(self, revision_options[:encoding]) if revision_options[:meta].is_a?(Hash) revision_options[:meta].each do |attribute, value| - case value - when Symbol - value = self.send(value) - when Proc - value = value.call(self) - end - revision.send("#{attribute}=", value) + set_revision_meta_attribute(revision, attribute, value) end + elsif revision_options[:meta].is_a?(Array) + revision_options[:meta].each do |attribute| + set_revision_meta_attribute(revision, attribute, attribute.to_sym) + end + elsif revision_options[:meta] + set_revision_meta_attribute(revision, revision_options[:meta], revision_options[:meta].to_sym) end revision.save! return revision @@ -299,7 +300,18 @@ def update_with_revision update_without_revision end end + + # Set an attribute based on a meta argument + def set_revision_meta_attribute(revision, attribute, value) + case value + when Symbol + value = self.send(value) + when Proc + value = value.call(self) + end + revision.send("#{attribute}=", value) + end end end -ActiveRecord::Base.send(:include, ActsAsRevisionable) +ActiveRecord::Base.extend(ActsAsRevisionable::ActsMethods) diff --git a/spec/acts_as_revisionable_spec.rb b/spec/acts_as_revisionable_spec.rb index f5b8559..5839c37 100644 --- a/spec/acts_as_revisionable_spec.rb +++ b/spec/acts_as_revisionable_spec.rb @@ -143,7 +143,7 @@ class RevisionableSubclassModel < RevisionableNamespaceModel context "injected methods" do it "should be able to inject revisionable behavior onto ActiveRecord::Base" do - ActiveRecord::Base.included_modules.should include(ActsAsRevisionable) + ActiveRecord::Base.should respond_to(:acts_as_revisionable) end it "should add as has_many :record_revisions association" do @@ -275,8 +275,8 @@ class RevisionableSubclassModel < RevisionableNamespaceModel record_1.create_revision! ActsAsRevisionable::RevisionRecord.count.should == 1 end - - it "should set metadata on the revison when creating a revision record" do + + it "should set metadata on the revison when creating a revision record using a complex attribute to value mapping" do record_1 = OtherRevisionableTestModel.create!(:name => "test", :updated_by => "dude") RevisionRecord2.count.should == 0 record_1.create_revision! @@ -286,6 +286,38 @@ class RevisionableSubclassModel < RevisionableNamespaceModel revision.updated_by.should == "dude" revision.version.should == 1 end + + it "should set metadata on the revison when creating a revision record using a simply string to define a method to copy" do + meta_value = OtherRevisionableTestModel.acts_as_revisionable_options[:meta] + begin + OtherRevisionableTestModel.acts_as_revisionable_options[:meta] = "label" + record_1 = OtherRevisionableTestModel.create!(:name => "test", :updated_by => "dude") + record_1.stub!(:label => "this is a label") + record_1.create_revision! + revision = record_1.last_revision + revision.label.should == "this is a label" + revision.updated_by.should == nil + revision.version.should == nil + ensure + OtherRevisionableTestModel.acts_as_revisionable_options[:meta] = meta_value + end + end + + it "should set metadata on the revison when creating a revision record using an array of attribute names to copy" do + meta_value = OtherRevisionableTestModel.acts_as_revisionable_options[:meta] + begin + OtherRevisionableTestModel.acts_as_revisionable_options[:meta] = [:label, "version"] + record_1 = OtherRevisionableTestModel.create!(:name => "test", :updated_by => "dude") + record_1.stub!(:label => "this is a label", :version => 100) + record_1.create_revision! + revision = record_1.last_revision + revision.label.should == "this is a label" + revision.updated_by.should == nil + revision.version.should == 100 + ensure + OtherRevisionableTestModel.acts_as_revisionable_options[:meta] = meta_value + end + end it "should not create a revision entry if revisioning is disabled" do record = RevisionableTestModel.create!(:name => "test")