Skip to content

Commit

Permalink
added ability to share a mixin with versioned class. changed the dyna…
Browse files Browse the repository at this point in the history
…mic version model to MyModel::Version. closes [12] and [13]

git-svn-id: http://svn.techno-weenie.net/projects/plugins/acts_as_versioned@553 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information
technoweenie committed Jan 2, 2006
1 parent 1d4e34a commit 5310c90
Show file tree
Hide file tree
Showing 5 changed files with 82 additions and 16 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
*0.3*

* (2 Jan 2005) added ability to share a mixin with versioned class
* (2 Jan 2005) changed the dynamic version model to MyModel::Version

*0.2.4*

* (27 Nov 2005) added note about possible destructive behavior of if_changed? [Michael Schuerig]
Expand Down
2 changes: 1 addition & 1 deletion Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ require 'rake/testtask'
require 'rake/contrib/rubyforgepublisher'

PKG_NAME = 'acts_as_versioned'
PKG_VERSION = '0.2.3'
PKG_VERSION = '0.3'
PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
PROD_HOST = "technoweenie@bidwell.textdrive.com"
RUBY_FORGE_PROJECT = 'ar-versioned'
Expand Down
54 changes: 47 additions & 7 deletions lib/acts_as_versioned.rb
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,40 @@ module ClassMethods
#
# * <tt>if_changed</tt> - Simple way of specifying attributes that are required to be changed before saving a model. This takes
# either a symbol or array of symbols. WARNING - This will attempt to overwrite any attribute setters you may have.
# Add this instead:
# Use this instead if you want to write your own attribute setters (and ignore if_changed):
#
# def name=(new_name)
# write_changed_attribute :name, new_name
# end
#
# * <tt>extend</tt> - Lets you specify a module to be mixed in both the original and versioned models. You can also just pass a block
# to create an anonymous mixin:
#
# 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?
#
# == Database Schema
#
# The model that you're versioning needs to have a 'version' attribute. The model is versioned
Expand All @@ -110,7 +138,7 @@ module ClassMethods
# end
# end
#
def acts_as_versioned(options = {})
def acts_as_versioned(options = {}, &extension)
# don't allow multiple calls
return if self.included_modules.include?(ActiveRecord::Acts::Versioned::ActMethods)

Expand All @@ -121,7 +149,7 @@ def acts_as_versioned(options = {})
attr_accessor :changed_attributes
end

self.versioned_class_name = options[:class_name] || "#{self.to_s.demodulize}Version"
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}#{Inflector.underscore(Inflector.demodulize(class_name_of_active_record_descendant(self)))}_versions#{table_name_suffix}"
self.versioned_inheritance_column = options[:inheritance_column] || "versioned_#{inheritance_column}"
Expand All @@ -130,9 +158,18 @@ def acts_as_versioned(options = {})
self.max_version_limit = options[:limit].to_i
self.version_condition = options[:if] || true

if block_given?
extension_module_name = "#{self.to_s}#{versioned_class_name}Extension"
silence_warnings do
Object.const_set(extension_module_name, Module.new(&extension))
end

options[:extend] = extension_module_name.constantize
end

class_eval do
has_many :versions,
:class_name => "ActiveRecord::Acts::Versioned::#{versioned_class_name}",
:class_name => "#{self.to_s}::#{versioned_class_name}",
:foreign_key => "#{versioned_foreign_key}",
:order => 'version'
before_save :set_new_version
Expand All @@ -150,16 +187,19 @@ def acts_as_versioned(options = {})
end
end
end

include options[:extend] if options[:extend].is_a?(Module)
end

# create the dynamic versioned model
# maybe if i sit down long enough i can think up a better way to do this.
dynamic_model = <<-EOV
class ActiveRecord::Acts::Versioned::#{versioned_class_name} < ActiveRecord::Base
class #{self.to_s}::#{versioned_class_name} < ActiveRecord::Base
set_table_name "#{versioned_table_name}"
belongs_to :#{self.to_s.demodulize.underscore}, :class_name => "#{self.to_s}"
EOV

dynamic_model += %Q{include #{options[:extend].to_s}\n} if options[:extend].is_a?(Module)
dynamic_model += %Q{set_sequence_name "#{version_sequence_name}"\n} if version_sequence_name

eval dynamic_model + 'end'
Expand Down Expand Up @@ -355,7 +395,7 @@ def versioned_columns

# Returns an instance of the dynamic versioned model
def versioned_class
"ActiveRecord::Acts::Versioned::#{versioned_class_name}".constantize
"#{self.to_s}::#{versioned_class_name}".constantize
end

# An array of fields that are not saved in the versioned table
Expand Down Expand Up @@ -404,4 +444,4 @@ def drop_versioned_table
end
end

ActiveRecord::Base.class_eval { include ActiveRecord::Acts::Versioned }
ActiveRecord::Base.send :include, ActiveRecord::Acts::Versioned
23 changes: 16 additions & 7 deletions test/fixtures/page.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
class Page < ActiveRecord::Base
cattr_accessor :feeling_good
@@feeling_good = true

acts_as_versioned :if => :feeling_good?
acts_as_versioned :if => :feeling_good? do
def self.included(base)
base.cattr_accessor :feeling_good
base.feeling_good = true
end

def feeling_good?
@@feeling_good == true
def feeling_good?
@@feeling_good == true
end
end
end

module LockedPageExtension
def hello_world
'hello_world'
end
end

Expand All @@ -17,7 +25,8 @@ class LockedPage < ActiveRecord::Base
:class_name => 'LockedPageRevision',
:version_column => :lock_version,
:limit => 2,
:if_changed => :title
:if_changed => :title,
:extend => LockedPageExtension
end

class SpecialLockedPage < LockedPage
Expand Down
14 changes: 13 additions & 1 deletion test/versioned_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,22 @@ def test_rollback_with_version_number
end

def test_versioned_class_name
assert_equal 'PageVersion', Page.versioned_class_name
assert_equal 'Version', Page.versioned_class_name
assert_equal 'LockedPageRevision', LockedPage.versioned_class_name
end

def test_versioned_class
assert_equal Page::Version, Page.versioned_class
assert_equal LockedPage::LockedPageRevision, LockedPage.versioned_class
end

def test_special_methods
assert_nothing_raised { pages(:welcome).feeling_good? }
assert_nothing_raised { pages(:welcome).versions.first.feeling_good? }
assert_nothing_raised { locked_pages(:welcome).hello_world }
assert_nothing_raised { locked_pages(:welcome).versions.first.hello_world }
end

def test_rollback_with_version_class
p = pages(:welcome)
assert_equal 24, p.version
Expand Down

0 comments on commit 5310c90

Please sign in to comment.