Navigate to an item's previous and next version.

This commit is contained in:
Andy Stewart 2010-06-22 14:41:26 +01:00
parent cc794c1002
commit b43400e33b
3 changed files with 81 additions and 4 deletions

View File

@ -142,7 +142,18 @@ In fact you could use PaperTrail to implement an undo system, though I haven't h
## Navigating Versions
Once you have a particular `version` of an item you can navigate to the previous and next versions.
You can call `previous_version` and `next_version` on an item to get it as it was/became. Note that these methods reify the item for you.
>> widget = Widget.find 42
>> widget.versions.length # 4 for example
>> widget = widget.previous_version # => widget == widget.versions.last.reify
>> widget = widget.previous_version # => widget == widget.versions[-2].reify
>> widget.next_version # => widget == widget.versions.last.reify
>> widget.next_version # nil
As an aside, I'm undecided about whether `widget.versions.last.next_version` should return `nil` or `self` (i.e. `widget`). Let me know if you have a view.
If instead you have a particular `version` of an item you can navigate to the previous and next versions.
>> widget = Widget.find 42
>> version = widget.versions[-2] # assuming widget has several versions

View File

@ -65,7 +65,7 @@ module PaperTrail
def record_update
if switched_on? && changed_and_we_care?
versions.build merge_metadata(:event => 'update',
:object => object_to_string(previous_version),
:object => object_to_string(item_before_change),
:whodunnit => PaperTrail.whodunnit)
end
end
@ -73,7 +73,7 @@ module PaperTrail
def record_destroy
if switched_on?
versions.create merge_metadata(:event => 'destroy',
:object => object_to_string(previous_version),
:object => object_to_string(item_before_change),
:whodunnit => PaperTrail.whodunnit)
end
end
@ -90,6 +90,20 @@ module PaperTrail
version.reify if version
end
# Returns the object (not a Version) as it was most recently.
def previous_version
last_version = version ? version.previous : versions.last
last_version.reify if last_version
end
# Returns the object (not a Version) as it became next.
def next_version
# NOTE: if self (the item) was not reified from a version, i.e. it is the
# "live" item, we return nil. Perhaps we should return self instead?
subsequent_version = version ? version.next : nil
subsequent_version.reify if subsequent_version
end
private
def merge_metadata(data)
@ -101,7 +115,7 @@ module PaperTrail
data.merge(PaperTrail.controller_info || {})
end
def previous_version
def item_before_change
previous = self.clone
previous.id = id
changes.each do |attr, ary|

View File

@ -512,6 +512,58 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
assert_equal @version, @widget.version
end
should 'return its previous self' do
assert_equal @widget.versions[-2].reify, @widget.previous_version
end
end
context 'A non-reified item' do
setup { @widget = Widget.new }
should 'not have a previous version' do
assert_nil @widget.previous_version
end
should 'not have a next version' do
assert_nil @widget.next_version
end
context 'with versions' do
setup do
@widget.save
%w( Tom Dick Jane ).each { |name| @widget.update_attributes :name => name }
end
should 'have a previous version' do
assert_equal @widget.versions.last.reify, @widget.previous_version
end
should 'have a next version' do
assert_nil @widget.next_version
end
end
end
context 'A reified item' do
setup do
widget = Widget.create :name => 'Bob'
%w( Tom Dick Jane ).each { |name| widget.update_attributes :name => name }
@versions = widget.versions
@second_widget = @versions[1].reify # first widget is null
@last_widget = @versions.last.reify
end
should 'have a previous version' do
assert_nil @second_widget.previous_version
assert_equal @versions[-2].reify, @last_widget.previous_version
end
should 'have a next version' do
assert_equal @versions[2].reify, @second_widget.next_version
assert_nil @last_widget.next_version
end
end