Skip to content

Commit

Permalink
add methods for paging between versions, like @page.versions.before(@…
Browse files Browse the repository at this point in the history
…page_version) or @page_version.previous

git-svn-id: http://svn.techno-weenie.net/projects/plugins/acts_as_versioned@2947 567b1171-46fb-0310-a4c9-b4bef9110e78
  • Loading branch information
technoweenie committed Aug 13, 2007
1 parent 5d616cd commit 18106f5
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 22 deletions.
65 changes: 50 additions & 15 deletions lib/acts_as_versioned.rb
Expand Up @@ -49,6 +49,21 @@ module Acts #:nodoc:
# page.revert_to(page.versions.last) # using versioned instance
# page.title # => 'hello world'
#
# page.versions.earliest # efficient query to find the first version
# page.versions.latest # efficient query to find the most recently created version
#
#
# Simple Queries to page between versions
#
# page.versions.before(version)
# page.versions.after(version)
#
# Access the previous/next versions from the versioned model itself
#
# version = page.versions.latest
# version.previous # go back one version
# version.next # go forward one version
#
# See ActiveRecord::Acts::Versioned::ClassMethods#acts_as_versioned for configuration options
module Versioned
CALLBACKS = [:set_new_version, :save_version_on_create, :save_version?, :clear_changed_attributes]
Expand Down Expand Up @@ -184,7 +199,7 @@ class << self
self.non_versioned_columns = [self.primary_key, inheritance_column, 'version', 'lock_version', versioned_inheritance_column]
self.version_association_options = {
:class_name => "#{self.to_s}::#{versioned_class_name}",
:foreign_key => "#{versioned_foreign_key}",
:foreign_key => versioned_foreign_key,
:order => 'version',
:dependent => :delete_all
}.merge(options[:association_options] || {})
Expand All @@ -199,7 +214,17 @@ class << self
end

class_eval do
has_many :versions, version_association_options
has_many :versions, version_association_options do
# finds earliest version of this record
def earliest
@earliest ||= find(:first)
end

# find latest version of this record
def latest
@latest ||= find(:first, :order => 'version desc')
end
end
before_save :set_new_version
after_create :save_version_on_create
after_update :save_version
Expand All @@ -222,8 +247,30 @@ class << self
# 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
end

versioned_class.cattr_accessor :original_class
versioned_class.original_class = self
puts versioned_class.original_class.inspect
versioned_class.set_table_name versioned_table_name
versioned_class.belongs_to self.to_s.demodulize.underscore.to_sym,
:class_name => "::#{self.to_s}",
Expand Down Expand Up @@ -263,24 +310,12 @@ def clear_old_versions
end
end

# Finds a specific version of this model.
def find_version(version)
return version if version.is_a?(self.class.versioned_class)
return nil if version.is_a?(ActiveRecord::Base)
find_versions(:conditions => ['version = ?', version], :limit => 1).first
end

# Finds versions of this model. Takes an options hash like <tt>find</tt>
def find_versions(options = {})
versions.find(:all, options)
end

# Reverts a model to a given version. Takes either a version number or an instance of the versioned model
def revert_to(version)
if version.is_a?(self.class.versioned_class)
return false unless version.send(self.class.versioned_foreign_key) == self.id and !version.new_record?
else
return false unless version = find_version(version)
return false unless version = versions.find_by_version(version)
end
self.clone_versioned_model(version, self)
self.send("#{self.class.version_column}=", version.version)
Expand Down
31 changes: 24 additions & 7 deletions test/versioned_test.rb
Expand Up @@ -4,6 +4,7 @@

class VersionedTest < Test::Unit::TestCase
fixtures :pages, :page_versions, :locked_pages, :locked_pages_revisions, :authors, :landmarks, :landmark_versions
set_fixture_class :page_versions => Page::Version

def test_saves_versioned_copy
p = Page.create! :title => 'first title', :body => 'first body'
Expand Down Expand Up @@ -209,8 +210,6 @@ def test_track_changed_attributes_default_value
def test_version_order
assert_equal 23, pages(:welcome).versions.first.version
assert_equal 24, pages(:welcome).versions.last.version
assert_equal 23, pages(:welcome).find_versions.first.version
assert_equal 24, pages(:welcome).find_versions.last.version
end

def test_track_changed_attributes
Expand Down Expand Up @@ -246,10 +245,10 @@ def assert_page_title(p, i, version_field = :version)

def test_find_versions
assert_equal 2, locked_pages(:welcome).versions.size
assert_equal 1, locked_pages(:welcome).find_versions(:conditions => ['title LIKE ?', '%weblog%']).length
assert_equal 2, locked_pages(:welcome).find_versions(:conditions => ['title LIKE ?', '%web%']).length
assert_equal 0, locked_pages(:thinking).find_versions(:conditions => ['title LIKE ?', '%web%']).length
assert_equal 2, locked_pages(:welcome).find_versions.length
assert_equal 1, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%weblog%']).length
assert_equal 2, locked_pages(:welcome).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length
assert_equal 0, locked_pages(:thinking).versions.find(:all, :conditions => ['title LIKE ?', '%web%']).length
assert_equal 2, locked_pages(:welcome).versions.length
end

def test_with_sequence
Expand Down Expand Up @@ -308,4 +307,22 @@ def test_unchanged_string_attributes
landmarks(:washington).attributes = landmarks(:washington).attributes.inject({}) { |params, (key, value)| params.update key => value.to_s }
assert !landmarks(:washington).changed?
end
end

def test_should_find_earliest_version
assert_equal page_versions(:welcome_1), pages(:welcome).versions.earliest
end

def test_should_find_latest_version
assert_equal page_versions(:welcome_2), pages(:welcome).versions.latest
end

def test_should_find_previous_version
assert_equal page_versions(:welcome_1), page_versions(:welcome_2).previous
assert_equal page_versions(:welcome_1), pages(:welcome).versions.before(page_versions(:welcome_2))
end

def test_should_find_next_version
assert_equal page_versions(:welcome_2), page_versions(:welcome_1).next
assert_equal page_versions(:welcome_2), pages(:welcome).versions.after(page_versions(:welcome_1))
end
end

0 comments on commit 18106f5

Please sign in to comment.