paper_trail 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
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.