paper_trail 1.5.0 → 1.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/README.md CHANGED
@@ -140,6 +140,37 @@ Undeleting is just as simple:
140
140
  In fact you could use PaperTrail to implement an undo system, though I haven't had the opportunity yet to do it myself.
141
141
 
142
142
 
143
+ ## Navigating Versions
144
+
145
+ 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.
146
+
147
+ >> widget = Widget.find 42
148
+ >> widget.versions.length # 4 for example
149
+ >> widget = widget.previous_version # => widget == widget.versions.last.reify
150
+ >> widget = widget.previous_version # => widget == widget.versions[-2].reify
151
+ >> widget.next_version # => widget == widget.versions.last.reify
152
+ >> widget.next_version # nil
153
+
154
+ 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.
155
+
156
+ If instead you have a particular `version` of an item you can navigate to the previous and next versions.
157
+
158
+ >> widget = Widget.find 42
159
+ >> version = widget.versions[-2] # assuming widget has several versions
160
+ >> previous = version.previous
161
+ >> next = version.next
162
+
163
+ You can find out which of an item's versions yours is:
164
+
165
+ >> current_version_number = version.index # 0-based
166
+
167
+ Finally, if you got an item by reifying one of its versions, you can navigate back to the version it came from:
168
+
169
+ >> latest_version = Widget.find(42).versions.last
170
+ >> widget = latest_version.reify
171
+ >> widget.version == latest_version # true
172
+
173
+
143
174
  ## Finding Out Who Was Responsible For A Change
144
175
 
145
176
  If your `ApplicationController` has a `current_user` method, PaperTrail will store the value it returns in the `version`'s `whodunnit` column. Note that this column is a string so you will have to convert it to an integer if it's an id and you want to look up the user later on:
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.5.0
1
+ 1.5.1
@@ -1,3 +1,4 @@
1
+ require 'singleton'
1
2
  require 'yaml'
2
3
  require 'paper_trail/config'
3
4
  require 'paper_trail/controller'
@@ -3,11 +3,13 @@ module PaperTrail
3
3
 
4
4
  def self.included(base)
5
5
  base.send :extend, ClassMethods
6
+
7
+ # The version this instance was reified from.
8
+ attr_accessor :version
6
9
  end
7
10
 
8
11
 
9
12
  module ClassMethods
10
-
11
13
  # Declare this in your model to track every create, update, and destroy. Each version of
12
14
  # the model is available in the `versions` association.
13
15
  #
@@ -18,6 +20,8 @@ module PaperTrail
18
20
  # trail). See `PaperTrail::Controller.info_for_paper_trail` for how to store data from
19
21
  # the controller.
20
22
  def has_paper_trail(options = {})
23
+ # Lazily include the instance methods so we don't clutter up
24
+ # any more ActiveRecord models than we have to.
21
25
  send :include, InstanceMethods
22
26
 
23
27
  cattr_accessor :ignore
@@ -49,7 +53,8 @@ module PaperTrail
49
53
  end
50
54
  end
51
55
 
52
-
56
+ # Wrap the following methods in a module so we can include them only in the
57
+ # ActiveRecord models that declare `has_paper_trail`.
53
58
  module InstanceMethods
54
59
  def record_create
55
60
  if switched_on?
@@ -60,7 +65,7 @@ module PaperTrail
60
65
  def record_update
61
66
  if switched_on? && changed_and_we_care?
62
67
  versions.build merge_metadata(:event => 'update',
63
- :object => object_to_string(previous_version),
68
+ :object => object_to_string(item_before_change),
64
69
  :whodunnit => PaperTrail.whodunnit)
65
70
  end
66
71
  end
@@ -68,7 +73,7 @@ module PaperTrail
68
73
  def record_destroy
69
74
  if switched_on?
70
75
  versions.create merge_metadata(:event => 'destroy',
71
- :object => object_to_string(previous_version),
76
+ :object => object_to_string(item_before_change),
72
77
  :whodunnit => PaperTrail.whodunnit)
73
78
  end
74
79
  end
@@ -81,10 +86,24 @@ module PaperTrail
81
86
  # timestamp because a version stores how the object looked before the
82
87
  # change.
83
88
  version = versions.first :conditions => ['created_at > ?', timestamp],
84
- :order => 'created_at ASC'
89
+ :order => 'created_at ASC'
85
90
  version.reify if version
86
91
  end
87
92
 
93
+ # Returns the object (not a Version) as it was most recently.
94
+ def previous_version
95
+ last_version = version ? version.previous : versions.last
96
+ last_version.reify if last_version
97
+ end
98
+
99
+ # Returns the object (not a Version) as it became next.
100
+ def next_version
101
+ # NOTE: if self (the item) was not reified from a version, i.e. it is the
102
+ # "live" item, we return nil. Perhaps we should return self instead?
103
+ subsequent_version = version ? version.next : nil
104
+ subsequent_version.reify if subsequent_version
105
+ end
106
+
88
107
  private
89
108
 
90
109
  def merge_metadata(data)
@@ -96,7 +115,7 @@ module PaperTrail
96
115
  data.merge(PaperTrail.controller_info || {})
97
116
  end
98
117
 
99
- def previous_version
118
+ def item_before_change
100
119
  previous = self.clone
101
120
  previous.id = id
102
121
  changes.each do |attr, ary|
@@ -4,8 +4,6 @@ class Version < ActiveRecord::Base
4
4
 
5
5
  def reify
6
6
  unless object.nil?
7
- # Attributes
8
-
9
7
  attrs = YAML::load object
10
8
 
11
9
  # Normally a polymorphic belongs_to relationship allows us
@@ -37,6 +35,7 @@ class Version < ActiveRecord::Base
37
35
  end
38
36
  end
39
37
 
38
+ model.version = self
40
39
  model
41
40
  end
42
41
  end
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{paper_trail}
8
- s.version = "1.5.0"
8
+ s.version = "1.5.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Andy Stewart"]
12
- s.date = %q{2010-03-19}
12
+ s.date = %q{2010-06-22}
13
13
  s.email = %q{boss@airbladesoftware.com}
14
14
  s.extra_rdoc_files = [
15
15
  "README.md"
@@ -44,7 +44,7 @@ Gem::Specification.new do |s|
44
44
  s.homepage = %q{http://github.com/airblade/paper_trail}
45
45
  s.rdoc_options = ["--charset=UTF-8"]
46
46
  s.require_paths = ["lib"]
47
- s.rubygems_version = %q{1.3.5}
47
+ s.rubygems_version = %q{1.3.7}
48
48
  s.summary = %q{Track changes to your models' data. Good for auditing or versioning.}
49
49
  s.test_files = [
50
50
  "test/paper_trail_controller_test.rb",
@@ -60,7 +60,7 @@ Gem::Specification.new do |s|
60
60
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
61
61
  s.specification_version = 3
62
62
 
63
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
63
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
64
64
  else
65
65
  end
66
66
  else
@@ -481,7 +481,7 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
481
481
  end
482
482
 
483
483
 
484
- context 'and destroyd' do
484
+ context 'and destroyed' do
485
485
  setup { @article.destroy }
486
486
 
487
487
  should 'store fixed meta data' do
@@ -500,5 +500,71 @@ class HasPaperTrailModelTest < Test::Unit::TestCase
500
500
  end
501
501
  end
502
502
 
503
+ context 'A reified item' do
504
+ setup do
505
+ widget = Widget.create :name => 'Bob'
506
+ %w( Tom Dick Jane ).each { |name| widget.update_attributes :name => name }
507
+ @version = widget.versions.last
508
+ @widget = @version.reify
509
+ end
510
+
511
+ should 'know which version it came from' do
512
+ assert_equal @version, @widget.version
513
+ end
514
+
515
+ should 'return its previous self' do
516
+ assert_equal @widget.versions[-2].reify, @widget.previous_version
517
+ end
518
+
519
+ end
520
+
521
+
522
+ context 'A non-reified item' do
523
+ setup { @widget = Widget.new }
524
+
525
+ should 'not have a previous version' do
526
+ assert_nil @widget.previous_version
527
+ end
528
+
529
+ should 'not have a next version' do
530
+ assert_nil @widget.next_version
531
+ end
532
+
533
+ context 'with versions' do
534
+ setup do
535
+ @widget.save
536
+ %w( Tom Dick Jane ).each { |name| @widget.update_attributes :name => name }
537
+ end
538
+
539
+ should 'have a previous version' do
540
+ assert_equal @widget.versions.last.reify, @widget.previous_version
541
+ end
542
+
543
+ should 'have a next version' do
544
+ assert_nil @widget.next_version
545
+ end
546
+ end
547
+ end
548
+
549
+ context 'A reified item' do
550
+ setup do
551
+ widget = Widget.create :name => 'Bob'
552
+ %w( Tom Dick Jane ).each { |name| widget.update_attributes :name => name }
553
+ @versions = widget.versions
554
+ @second_widget = @versions[1].reify # first widget is null
555
+ @last_widget = @versions.last.reify
556
+ end
557
+
558
+ should 'have a previous version' do
559
+ assert_nil @second_widget.previous_version
560
+ assert_equal @versions[-2].reify, @last_widget.previous_version
561
+ end
562
+
563
+ should 'have a next version' do
564
+ assert_equal @versions[2].reify, @second_widget.next_version
565
+ assert_nil @last_widget.next_version
566
+ end
567
+ end
568
+
503
569
 
504
570
  end
@@ -45,8 +45,8 @@ ActiveRecord::Schema.define(:version => 0) do
45
45
  end
46
46
 
47
47
  create_table :articles, :force => true do |t|
48
- t.integer :title
49
- t.string :content
48
+ t.string :title
49
+ t.string :content
50
50
  end
51
51
 
52
52
  end
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paper_trail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.0
4
+ hash: 1
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 5
9
+ - 1
10
+ version: 1.5.1
5
11
  platform: ruby
6
12
  authors:
7
13
  - Andy Stewart
@@ -9,7 +15,7 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-03-19 00:00:00 +00:00
18
+ date: 2010-06-22 00:00:00 +01:00
13
19
  default_executable:
14
20
  dependencies: []
15
21
 
@@ -57,21 +63,27 @@ rdoc_options:
57
63
  require_paths:
58
64
  - lib
59
65
  required_ruby_version: !ruby/object:Gem::Requirement
66
+ none: false
60
67
  requirements:
61
68
  - - ">="
62
69
  - !ruby/object:Gem::Version
70
+ hash: 3
71
+ segments:
72
+ - 0
63
73
  version: "0"
64
- version:
65
74
  required_rubygems_version: !ruby/object:Gem::Requirement
75
+ none: false
66
76
  requirements:
67
77
  - - ">="
68
78
  - !ruby/object:Gem::Version
79
+ hash: 3
80
+ segments:
81
+ - 0
69
82
  version: "0"
70
- version:
71
83
  requirements: []
72
84
 
73
85
  rubyforge_project:
74
- rubygems_version: 1.3.5
86
+ rubygems_version: 1.3.7
75
87
  signing_key:
76
88
  specification_version: 3
77
89
  summary: Track changes to your models' data. Good for auditing or versioning.