paper_trail 4.2.0 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (171) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/paper_trail/install_generator.rb +91 -17
  3. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb.erb +12 -0
  4. data/lib/generators/paper_trail/templates/{add_transaction_id_column_to_versions.rb → add_transaction_id_column_to_versions.rb.erb} +3 -1
  5. data/lib/generators/paper_trail/templates/create_version_associations.rb.erb +22 -0
  6. data/lib/generators/paper_trail/templates/{create_versions.rb → create_versions.rb.erb} +9 -7
  7. data/lib/paper_trail.rb +180 -148
  8. data/lib/paper_trail/attribute_serializers/README.md +10 -0
  9. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +80 -0
  10. data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +48 -0
  11. data/lib/paper_trail/attribute_serializers/object_attribute.rb +39 -0
  12. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +42 -0
  13. data/lib/paper_trail/cleaner.rb +16 -10
  14. data/lib/paper_trail/config.rb +28 -27
  15. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +5 -1
  16. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +6 -2
  17. data/lib/paper_trail/frameworks/cucumber.rb +1 -0
  18. data/lib/paper_trail/frameworks/rails.rb +2 -7
  19. data/lib/paper_trail/frameworks/rails/controller.rb +20 -18
  20. data/lib/paper_trail/frameworks/rails/engine.rb +6 -1
  21. data/lib/paper_trail/frameworks/rspec.rb +17 -6
  22. data/lib/paper_trail/frameworks/rspec/helpers.rb +3 -1
  23. data/lib/paper_trail/has_paper_trail.rb +25 -503
  24. data/lib/paper_trail/model_config.rb +207 -0
  25. data/lib/paper_trail/queries/versions/where_object.rb +60 -0
  26. data/lib/paper_trail/queries/versions/where_object_changes.rb +68 -0
  27. data/lib/paper_trail/record_history.rb +2 -12
  28. data/lib/paper_trail/record_trail.rb +573 -0
  29. data/lib/paper_trail/reifier.rb +164 -215
  30. data/lib/paper_trail/reifiers/belongs_to.rb +48 -0
  31. data/lib/paper_trail/reifiers/has_and_belongs_to_many.rb +50 -0
  32. data/lib/paper_trail/reifiers/has_many.rb +110 -0
  33. data/lib/paper_trail/reifiers/has_many_through.rb +90 -0
  34. data/lib/paper_trail/reifiers/has_one.rb +76 -0
  35. data/lib/paper_trail/serializers/json.rb +16 -7
  36. data/lib/paper_trail/serializers/yaml.rb +9 -13
  37. data/lib/paper_trail/version_association_concern.rb +3 -5
  38. data/lib/paper_trail/version_concern.rb +138 -111
  39. data/lib/paper_trail/version_number.rb +10 -9
  40. metadata +95 -327
  41. data/.gitignore +0 -22
  42. data/.rspec +0 -2
  43. data/.travis.yml +0 -41
  44. data/CHANGELOG.md +0 -362
  45. data/CONTRIBUTING.md +0 -84
  46. data/Gemfile +0 -2
  47. data/MIT-LICENSE +0 -20
  48. data/README.md +0 -1535
  49. data/Rakefile +0 -30
  50. data/doc/bug_report_template.rb +0 -65
  51. data/gemfiles/ar3.gemfile +0 -61
  52. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +0 -10
  53. data/lib/generators/paper_trail/templates/create_version_associations.rb +0 -17
  54. data/lib/paper_trail/attributes_serialization.rb +0 -89
  55. data/lib/paper_trail/frameworks/sinatra.rb +0 -38
  56. data/paper_trail.gemspec +0 -59
  57. data/spec/generators/install_generator_spec.rb +0 -67
  58. data/spec/models/animal_spec.rb +0 -36
  59. data/spec/models/boolit_spec.rb +0 -48
  60. data/spec/models/callback_modifier_spec.rb +0 -96
  61. data/spec/models/fluxor_spec.rb +0 -19
  62. data/spec/models/gadget_spec.rb +0 -70
  63. data/spec/models/joined_version_spec.rb +0 -47
  64. data/spec/models/json_version_spec.rb +0 -103
  65. data/spec/models/kitchen/banana_spec.rb +0 -14
  66. data/spec/models/not_on_update_spec.rb +0 -19
  67. data/spec/models/post_with_status_spec.rb +0 -17
  68. data/spec/models/skipper_spec.rb +0 -46
  69. data/spec/models/thing_spec.rb +0 -11
  70. data/spec/models/version_spec.rb +0 -239
  71. data/spec/models/widget_spec.rb +0 -298
  72. data/spec/modules/paper_trail_spec.rb +0 -27
  73. data/spec/modules/version_concern_spec.rb +0 -32
  74. data/spec/modules/version_number_spec.rb +0 -44
  75. data/spec/paper_trail/config_spec.rb +0 -52
  76. data/spec/paper_trail_spec.rb +0 -66
  77. data/spec/rails_helper.rb +0 -34
  78. data/spec/requests/articles_spec.rb +0 -30
  79. data/spec/spec_helper.rb +0 -95
  80. data/spec/support/alt_db_init.rb +0 -59
  81. data/test/custom_json_serializer.rb +0 -13
  82. data/test/dummy/Rakefile +0 -7
  83. data/test/dummy/app/controllers/application_controller.rb +0 -20
  84. data/test/dummy/app/controllers/articles_controller.rb +0 -17
  85. data/test/dummy/app/controllers/test_controller.rb +0 -5
  86. data/test/dummy/app/controllers/widgets_controller.rb +0 -31
  87. data/test/dummy/app/helpers/application_helper.rb +0 -2
  88. data/test/dummy/app/models/animal.rb +0 -6
  89. data/test/dummy/app/models/article.rb +0 -16
  90. data/test/dummy/app/models/authorship.rb +0 -5
  91. data/test/dummy/app/models/book.rb +0 -9
  92. data/test/dummy/app/models/boolit.rb +0 -4
  93. data/test/dummy/app/models/callback_modifier.rb +0 -45
  94. data/test/dummy/app/models/cat.rb +0 -2
  95. data/test/dummy/app/models/chapter.rb +0 -9
  96. data/test/dummy/app/models/citation.rb +0 -5
  97. data/test/dummy/app/models/customer.rb +0 -4
  98. data/test/dummy/app/models/document.rb +0 -4
  99. data/test/dummy/app/models/dog.rb +0 -2
  100. data/test/dummy/app/models/editor.rb +0 -4
  101. data/test/dummy/app/models/editorship.rb +0 -5
  102. data/test/dummy/app/models/elephant.rb +0 -3
  103. data/test/dummy/app/models/fluxor.rb +0 -3
  104. data/test/dummy/app/models/foo_widget.rb +0 -2
  105. data/test/dummy/app/models/fruit.rb +0 -5
  106. data/test/dummy/app/models/gadget.rb +0 -3
  107. data/test/dummy/app/models/kitchen/banana.rb +0 -5
  108. data/test/dummy/app/models/legacy_widget.rb +0 -4
  109. data/test/dummy/app/models/line_item.rb +0 -4
  110. data/test/dummy/app/models/not_on_update.rb +0 -4
  111. data/test/dummy/app/models/order.rb +0 -5
  112. data/test/dummy/app/models/paragraph.rb +0 -5
  113. data/test/dummy/app/models/person.rb +0 -38
  114. data/test/dummy/app/models/post.rb +0 -3
  115. data/test/dummy/app/models/post_with_status.rb +0 -8
  116. data/test/dummy/app/models/protected_widget.rb +0 -3
  117. data/test/dummy/app/models/quotation.rb +0 -5
  118. data/test/dummy/app/models/section.rb +0 -6
  119. data/test/dummy/app/models/skipper.rb +0 -6
  120. data/test/dummy/app/models/song.rb +0 -32
  121. data/test/dummy/app/models/thing.rb +0 -3
  122. data/test/dummy/app/models/translation.rb +0 -4
  123. data/test/dummy/app/models/whatchamajigger.rb +0 -4
  124. data/test/dummy/app/models/widget.rb +0 -15
  125. data/test/dummy/app/models/wotsit.rb +0 -8
  126. data/test/dummy/app/versions/joined_version.rb +0 -5
  127. data/test/dummy/app/versions/json_version.rb +0 -3
  128. data/test/dummy/app/versions/kitchen/banana_version.rb +0 -5
  129. data/test/dummy/app/versions/post_version.rb +0 -3
  130. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  131. data/test/dummy/config.ru +0 -4
  132. data/test/dummy/config/application.rb +0 -69
  133. data/test/dummy/config/boot.rb +0 -10
  134. data/test/dummy/config/database.mysql.yml +0 -19
  135. data/test/dummy/config/database.postgres.yml +0 -15
  136. data/test/dummy/config/database.sqlite.yml +0 -15
  137. data/test/dummy/config/environment.rb +0 -5
  138. data/test/dummy/config/environments/development.rb +0 -40
  139. data/test/dummy/config/environments/production.rb +0 -73
  140. data/test/dummy/config/environments/test.rb +0 -41
  141. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -7
  142. data/test/dummy/config/initializers/inflections.rb +0 -10
  143. data/test/dummy/config/initializers/mime_types.rb +0 -5
  144. data/test/dummy/config/initializers/paper_trail.rb +0 -10
  145. data/test/dummy/config/initializers/secret_token.rb +0 -7
  146. data/test/dummy/config/initializers/session_store.rb +0 -8
  147. data/test/dummy/config/locales/en.yml +0 -5
  148. data/test/dummy/config/routes.rb +0 -4
  149. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +0 -287
  150. data/test/dummy/db/schema.rb +0 -246
  151. data/test/dummy/script/rails +0 -6
  152. data/test/functional/controller_test.rb +0 -91
  153. data/test/functional/enabled_for_controller_test.rb +0 -29
  154. data/test/functional/modular_sinatra_test.rb +0 -48
  155. data/test/functional/sinatra_test.rb +0 -49
  156. data/test/functional/thread_safety_test.rb +0 -48
  157. data/test/paper_trail_test.rb +0 -38
  158. data/test/test_helper.rb +0 -105
  159. data/test/time_travel_helper.rb +0 -15
  160. data/test/unit/associations_test.rb +0 -726
  161. data/test/unit/cleaner_test.rb +0 -182
  162. data/test/unit/inheritance_column_test.rb +0 -43
  163. data/test/unit/model_test.rb +0 -1373
  164. data/test/unit/protected_attrs_test.rb +0 -47
  165. data/test/unit/serializer_test.rb +0 -117
  166. data/test/unit/serializers/json_test.rb +0 -88
  167. data/test/unit/serializers/mixin_json_test.rb +0 -36
  168. data/test/unit/serializers/mixin_yaml_test.rb +0 -49
  169. data/test/unit/serializers/yaml_test.rb +0 -52
  170. data/test/unit/timestamp_test.rb +0 -43
  171. data/test/unit/version_test.rb +0 -119
@@ -1,17 +0,0 @@
1
- require 'rails_helper'
2
-
3
- # This model is in the test suite soley for the purpose of testing ActiveRecord::Enum,
4
- # which is available in ActiveRecord4+ only
5
- describe PostWithStatus, :type => :model do
6
- if defined?(ActiveRecord::Enum)
7
- with_versioning do
8
- let(:post) { PostWithStatus.create!(:status => 'draft') }
9
-
10
- it "should stash the enum value properly in versions" do
11
- post.published!
12
- post.archived!
13
- expect(post.previous_version.published?).to be true
14
- end
15
- end
16
- end
17
- end
@@ -1,46 +0,0 @@
1
- require 'rails_helper'
2
-
3
- describe Skipper, :type => :model do
4
- with_versioning do
5
- it { is_expected.to be_versioned }
6
-
7
- describe "#update_attributes!", :versioning => true do
8
- context "updating a skipped attribute" do
9
- let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
10
- let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
11
-
12
- it "should not create a version" do
13
- skipper = Skipper.create!(:another_timestamp => t1)
14
- expect {
15
- skipper.update_attributes!(:another_timestamp => t2)
16
- }.to_not change { skipper.versions.length }
17
- end
18
- end
19
- end
20
-
21
- describe "reify" do
22
- context "reifying a with a skipped attribute" do
23
- let(:t1) { Time.zone.local(2015, 7, 15, 20, 34, 0) }
24
- let(:t2) { Time.zone.local(2015, 7, 15, 20, 34, 30) }
25
-
26
- context "without preserve (default)" do
27
- it "should have no timestamp" do
28
- skipper = Skipper.create!(:another_timestamp => t1)
29
- skipper.update_attributes!(:another_timestamp => t2, :name => "Foobar")
30
- skipper = skipper.versions.last.reify
31
- expect(skipper.another_timestamp).to be(nil)
32
- end
33
- end
34
-
35
- context "with preserve" do
36
- it "should preserve its timestamp" do
37
- skipper = Skipper.create!(:another_timestamp => t1)
38
- skipper.update_attributes!(:another_timestamp => t2, :name => "Foobar")
39
- skipper = skipper.versions.last.reify(:unversioned_attributes => :preserve)
40
- expect(skipper.another_timestamp).to eq(t2)
41
- end
42
- end
43
- end
44
- end
45
- end
46
- end
@@ -1,11 +0,0 @@
1
- require 'rails_helper'
2
-
3
- describe Thing, :type => :model do
4
- it { is_expected.to be_versioned }
5
-
6
- describe "should not store object_changes", :versioning => true do
7
- let(:thing) { Thing.create(:name =>"pencil") }
8
-
9
- it { expect(thing.versions.last.object_changes).to be_nil }
10
- end
11
- end
@@ -1,239 +0,0 @@
1
- require 'rails_helper'
2
-
3
- describe PaperTrail::Version, :type => :model do
4
- it "should include the `VersionConcern` module to get base functionality" do
5
- expect(PaperTrail::Version).to include(PaperTrail::VersionConcern)
6
- end
7
-
8
- describe "Attributes" do
9
- it { is_expected.to have_db_column(:item_type).of_type(:string) }
10
- it { is_expected.to have_db_column(:item_id).of_type(:integer) }
11
- it { is_expected.to have_db_column(:event).of_type(:string) }
12
- it { is_expected.to have_db_column(:whodunnit).of_type(:string) }
13
- it { is_expected.to have_db_column(:object).of_type(:text) }
14
- it { is_expected.to have_db_column(:created_at).of_type(:datetime) }
15
-
16
- describe "object_changes column", :versioning => true do
17
- let(:widget) { Widget.create!(:name => 'Dashboard') }
18
- let(:value) { widget.versions.last.object_changes }
19
-
20
- context "serializer is YAML" do
21
- specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
22
-
23
- it "should store out as a plain hash" do
24
- expect(value =~ /HashWithIndifferentAccess/).to be_nil
25
- end
26
- end
27
-
28
- context "serializer is JSON" do
29
- before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
30
-
31
- it "should store out as a plain hash" do
32
- expect(value =~ /HashWithIndifferentAccess/).to be_nil
33
- end
34
-
35
- after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
36
- end
37
- end
38
- end
39
-
40
- describe "Indexes" do
41
- it { is_expected.to have_db_index([:item_type, :item_id]) }
42
- end
43
-
44
- describe "Methods" do
45
- describe "Instance" do
46
- subject { PaperTrail::Version.new(attributes) rescue PaperTrail::Version.new }
47
-
48
- describe '#paper_trail_originator' do
49
- it { is_expected.to respond_to(:paper_trail_originator) }
50
-
51
- context "No previous versions" do
52
- specify { expect(subject.previous).to be_nil }
53
-
54
- it "should return nil" do
55
- expect(subject.paper_trail_originator).to be_nil
56
- end
57
- end
58
-
59
- context "Has previous version", :versioning => true do
60
- let(:name) { Faker::Name.name }
61
- let(:widget) { Widget.create!(:name => Faker::Name.name) }
62
- before do
63
- widget.versions.first.update_attributes!(:whodunnit => name)
64
- widget.update_attributes!(:name => Faker::Name.first_name)
65
- end
66
- subject { widget.versions.last }
67
-
68
- specify { expect(subject.previous).to be_instance_of(PaperTrail::Version) }
69
-
70
- it "should return nil" do
71
- expect(subject.paper_trail_originator).to eq(name)
72
- end
73
- end
74
- end
75
-
76
- describe "#originator" do
77
- it { is_expected.to respond_to(:originator) }
78
-
79
- it 'should set the invoke `paper_trail_originator`' do
80
- allow(ActiveSupport::Deprecation).to receive(:warn)
81
- is_expected.to receive(:paper_trail_originator)
82
- subject.originator
83
- end
84
-
85
- it 'should display a deprecation warning' do
86
- expect(ActiveSupport::Deprecation).to receive(:warn).
87
- with(/Use paper_trail_originator instead of originator/)
88
- subject.originator
89
- end
90
- end
91
-
92
- describe '#terminator' do
93
- it { is_expected.to respond_to(:terminator) }
94
-
95
- let(:attributes) { {:whodunnit => Faker::Name.first_name} }
96
-
97
- it "is an alias for the `whodunnit` attribute" do
98
- expect(subject.terminator).to eq(attributes[:whodunnit])
99
- end
100
- end
101
-
102
- describe '#version_author' do
103
- it { is_expected.to respond_to(:version_author) }
104
-
105
- it "should be an alias for the `terminator` method" do
106
- expect(subject.method(:version_author)).to eq(subject.method(:terminator))
107
- end
108
- end
109
- end
110
-
111
- describe "Class" do
112
- column_overrides = [false]
113
- if ENV['DB'] == 'postgres' && ::ActiveRecord::VERSION::MAJOR >= 4
114
- column_overrides << 'json'
115
- # 'jsonb' column types are only supported for ActiveRecord 4.2+
116
- column_overrides << 'jsonb' if ::ActiveRecord::VERSION::STRING >= '4.2'
117
- end
118
-
119
- column_overrides.shuffle.each do |override|
120
- context "with a #{override || 'text'} column" do
121
- before do
122
- if override
123
- ActiveRecord::Base.connection.execute("SAVEPOINT pgtest;")
124
- %w[object object_changes].each do |column|
125
- ActiveRecord::Base.connection.execute("ALTER TABLE versions DROP COLUMN #{column};")
126
- ActiveRecord::Base.connection.execute("ALTER TABLE versions ADD COLUMN #{column} #{override};")
127
- end
128
- PaperTrail::Version.reset_column_information
129
- end
130
- end
131
- after do
132
- if override
133
- ActiveRecord::Base.connection.execute("ROLLBACK TO SAVEPOINT pgtest;")
134
- PaperTrail::Version.reset_column_information
135
- end
136
- end
137
-
138
- describe '#where_object' do
139
- it { expect(PaperTrail::Version).to respond_to(:where_object) }
140
-
141
- context "invalid arguments" do
142
- it "should raise an error" do
143
- expect { PaperTrail::Version.where_object(:foo) }.to raise_error(ArgumentError)
144
- expect { PaperTrail::Version.where_object([]) }.to raise_error(ArgumentError)
145
- end
146
- end
147
-
148
- context "valid arguments", :versioning => true do
149
- let(:widget) { Widget.new }
150
- let(:name) { Faker::Name.first_name }
151
- let(:int) { rand(10) + 1 }
152
-
153
- before do
154
- widget.update_attributes!(:name => name, :an_integer => int)
155
- widget.update_attributes!(:name => 'foobar', :an_integer => 100)
156
- widget.update_attributes!(:name => Faker::Name.last_name, :an_integer => 15)
157
- end
158
-
159
- context "`serializer == YAML`" do
160
- specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
161
-
162
- it "should be able to locate versions according to their `object` contents" do
163
- expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
164
- expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
165
- end
166
- end
167
-
168
- context "`serializer == JSON`" do
169
- before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
170
- specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON }
171
-
172
- it "should be able to locate versions according to their `object` contents" do
173
- expect(PaperTrail::Version.where_object(:name => name)).to eq([widget.versions[1]])
174
- expect(PaperTrail::Version.where_object(:an_integer => 100)).to eq([widget.versions[2]])
175
- end
176
-
177
- after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
178
- end
179
- end
180
- end
181
-
182
- describe '#where_object_changes' do
183
- it { expect(PaperTrail::Version).to respond_to(:where_object_changes) }
184
-
185
- context "invalid arguments" do
186
- it "should raise an error" do
187
- expect { PaperTrail::Version.where_object_changes(:foo) }.to raise_error(ArgumentError)
188
- expect { PaperTrail::Version.where_object_changes([]) }.to raise_error(ArgumentError)
189
- end
190
- end
191
-
192
- context "valid arguments", :versioning => true do
193
- let(:widget) { Widget.new }
194
- let(:name) { Faker::Name.first_name }
195
- let(:int) { rand(5) + 2 }
196
-
197
- before do
198
- widget.update_attributes!(:name => name, :an_integer => 0)
199
- widget.update_attributes!(:name => 'foobar', :an_integer => 77)
200
- widget.update_attributes!(:name => Faker::Name.last_name, :an_integer => int)
201
- end
202
-
203
- context "`serializer == YAML`" do
204
- specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::YAML }
205
-
206
- it "should be able to locate versions according to their `object_changes` contents" do
207
- expect(widget.versions.where_object_changes(:name => name)).to eq(widget.versions[0..1])
208
- expect(widget.versions.where_object_changes(:an_integer => 77)).to eq(widget.versions[1..2])
209
- expect(widget.versions.where_object_changes(:an_integer => int)).to eq([widget.versions.last])
210
- end
211
-
212
- it "should be able to handle queries for multiple attributes" do
213
- expect(widget.versions.where_object_changes(:an_integer => 77, :name => 'foobar')).to eq(widget.versions[1..2])
214
- end
215
- end
216
-
217
- context "`serializer == JSON`" do
218
- before(:all) { PaperTrail.serializer = PaperTrail::Serializers::JSON }
219
- specify { expect(PaperTrail.serializer).to be PaperTrail::Serializers::JSON }
220
-
221
- it "should be able to locate versions according to their `object_changes` contents" do
222
- expect(widget.versions.where_object_changes(:name => name)).to eq(widget.versions[0..1])
223
- expect(widget.versions.where_object_changes(:an_integer => 77)).to eq(widget.versions[1..2])
224
- expect(widget.versions.where_object_changes(:an_integer => int)).to eq([widget.versions.last])
225
- end
226
-
227
- it "should be able to handle queries for multiple attributes" do
228
- expect(widget.versions.where_object_changes(:an_integer => 77, :name => 'foobar')).to eq(widget.versions[1..2])
229
- end
230
-
231
- after(:all) { PaperTrail.serializer = PaperTrail::Serializers::YAML }
232
- end
233
- end
234
- end
235
- end
236
- end
237
- end
238
- end
239
- end
@@ -1,298 +0,0 @@
1
- require 'rails_helper'
2
-
3
- describe Widget, :type => :model do
4
- describe '`be_versioned` matcher' do
5
- it { is_expected.to be_versioned }
6
- end
7
-
8
- let(:widget) { Widget.create! :name => 'Bob', :an_integer => 1 }
9
-
10
- describe '`have_a_version_with` matcher', :versioning => true do
11
- before do
12
- widget.update_attributes!(:name => 'Leonard', :an_integer => 1 )
13
- widget.update_attributes!(:name => 'Tom')
14
- widget.update_attributes!(:name => 'Bob')
15
- end
16
-
17
- it "is possible to do assertions on versions" do
18
- expect(widget).to have_a_version_with :name => 'Leonard', :an_integer => 1
19
- expect(widget).to have_a_version_with :an_integer => 1
20
- expect(widget).to have_a_version_with :name => 'Tom'
21
- end
22
- end
23
-
24
- describe "`versioning` option" do
25
- context :enabled, :versioning => true do
26
- it 'should enable versioning for models wrapped within a block' do
27
- expect(widget.versions.size).to eq(1)
28
- end
29
- end
30
-
31
- context '`disabled` (default)' do
32
- it 'should not enable versioning for models wrapped within a block not marked to used versioning' do
33
- expect(widget.versions.size).to eq(0)
34
- end
35
- end
36
- end
37
-
38
- describe "Callbacks", :versioning => true do
39
- describe :before_save do
40
- context ':on => :update' do
41
- before { widget.update_attributes!(:name => 'Foobar') }
42
-
43
- subject { widget.versions.last.reify }
44
-
45
- it "should reset the value for the timestamp attrs for update so that value gets updated properly" do
46
- expect { subject.save! }.to change(subject, :updated_at)
47
- end
48
- end
49
- end
50
-
51
- describe :after_create do
52
- let(:widget) { Widget.create!(:name => 'Foobar', :created_at => Time.now - 1.week) }
53
-
54
- it "corresponding version should use the widget's `updated_at`" do
55
- expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
56
- end
57
- end
58
-
59
- describe :after_update do
60
- before { widget.update_attributes!(:name => 'Foobar', :updated_at => Time.now + 1.week) }
61
-
62
- subject { widget.versions.last.reify }
63
-
64
- it { expect(subject).not_to be_live }
65
-
66
- it "should clear the `versions_association_name` virtual attribute" do
67
- subject.save!
68
- expect(subject).to be_live
69
- end
70
-
71
- it "corresponding version should use the widget updated_at" do
72
- expect(widget.versions.last.created_at.to_i).to eq(widget.updated_at.to_i)
73
- end
74
- end
75
-
76
- describe :after_destroy do
77
- it "should create a version for that event" do
78
- expect { widget.destroy }.to change(widget.versions, :count).by(1)
79
- end
80
-
81
- it "should assign the version into the `versions_association_name`" do
82
- expect(widget.version).to be_nil
83
- widget.destroy
84
- expect(widget.version).not_to be_nil
85
- expect(widget.version).to eq(widget.versions.last)
86
- end
87
- end
88
-
89
- describe :after_rollback do
90
- let(:rolled_back_name) { 'Big Moo' }
91
-
92
- before do
93
- begin
94
- widget.transaction do
95
- widget.update_attributes!(:name => rolled_back_name)
96
- widget.update_attributes!(:name => Widget::EXCLUDED_NAME)
97
- end
98
- rescue ActiveRecord::RecordInvalid
99
- widget.reload
100
- widget.name = nil
101
- widget.save
102
- end
103
- end
104
-
105
- it 'does not create an event for changes that did not happen' do
106
- widget.versions.map(&:changeset).each do |changeset|
107
- expect(changeset.fetch('name', [])).to_not include(rolled_back_name)
108
- end
109
- end
110
- end
111
- end
112
-
113
- describe "Association", :versioning => true do
114
- describe "sort order" do
115
- it "should sort by the timestamp order from the `VersionConcern`" do
116
- expect(widget.versions.to_sql).to eq(
117
- widget.versions.reorder(PaperTrail::Version.timestamp_sort_order).to_sql)
118
- end
119
- end
120
- end
121
-
122
- describe "Methods" do
123
- describe "Instance", :versioning => true do
124
- describe '#paper_trail_originator' do
125
- it { is_expected.to respond_to(:paper_trail_originator) }
126
-
127
- describe "return value" do
128
- let(:orig_name) { Faker::Name.name }
129
- let(:new_name) { Faker::Name.name }
130
- before { PaperTrail.whodunnit = orig_name }
131
-
132
- context "accessed from live model instance" do
133
- specify { expect(widget).to be_live }
134
-
135
- it "should return the originator for the model at a given state" do
136
- expect(widget.paper_trail_originator).to eq(orig_name)
137
- widget.whodunnit(new_name) { |w| w.update_attributes(:name => 'Elizabeth') }
138
- expect(widget.paper_trail_originator).to eq(new_name)
139
- end
140
- end
141
-
142
- context "accessed from a reified model instance" do
143
- before do
144
- widget.update_attributes(:name => 'Andy')
145
- PaperTrail.whodunnit = new_name
146
- widget.update_attributes(:name => 'Elizabeth')
147
- end
148
-
149
- context "default behavior (no `options[:dup]` option passed in)" do
150
- let(:reified_widget) { widget.versions[1].reify }
151
-
152
- it "should return the appropriate originator" do
153
- expect(reified_widget.paper_trail_originator).to eq(orig_name)
154
- end
155
-
156
- it "should not create a new model instance" do
157
- expect(reified_widget).not_to be_new_record
158
- end
159
- end
160
-
161
- context "creating a new instance (`options[:dup] == true`)" do
162
- let(:reified_widget) { widget.versions[1].reify(:dup => true) }
163
-
164
- it "should return the appropriate originator" do
165
- expect(reified_widget.paper_trail_originator).to eq(orig_name)
166
- end
167
-
168
- it "should not create a new model instance" do
169
- expect(reified_widget).to be_new_record
170
- end
171
- end
172
- end
173
- end
174
- end
175
-
176
- describe "#originator" do
177
- subject { widget }
178
-
179
- it { is_expected.to respond_to(:originator) }
180
-
181
- it 'should set the invoke `paper_trail_originator`' do
182
- allow(::ActiveSupport::Deprecation).to receive(:warn)
183
- is_expected.to receive(:paper_trail_originator)
184
- subject.originator
185
- end
186
-
187
- it 'should display a deprecation warning' do
188
- expect(::ActiveSupport::Deprecation).to receive(:warn).
189
- with(/Use paper_trail_originator instead of originator/)
190
- subject.originator
191
- end
192
- end
193
-
194
- describe '#version_at' do
195
- it { is_expected.to respond_to(:version_at) }
196
-
197
- context "Timestamp argument is AFTER object has been destroyed" do
198
- before do
199
- widget.update_attribute(:name, 'foobar')
200
- widget.destroy
201
- end
202
-
203
- it "should return `nil`" do
204
- expect(widget.version_at(Time.now)).to be_nil
205
- end
206
- end
207
- end
208
-
209
- describe '#whodunnit' do
210
- it { is_expected.to respond_to(:whodunnit) }
211
-
212
- context "no block given" do
213
- it "should raise an error" do
214
- expect { widget.whodunnit('Ben') }.to raise_error(ArgumentError, 'expected to receive a block')
215
- end
216
- end
217
-
218
- context "block given" do
219
- let(:orig_name) { Faker::Name.name }
220
- let(:new_name) { Faker::Name.name }
221
-
222
- before do
223
- PaperTrail.whodunnit = orig_name
224
- expect(widget.versions.last.whodunnit).to eq(orig_name) # persist `widget`
225
- end
226
-
227
- it "should modify value of `PaperTrail.whodunnit` while executing the block" do
228
- widget.whodunnit(new_name) do
229
- expect(PaperTrail.whodunnit).to eq(new_name)
230
- widget.update_attributes(:name => 'Elizabeth')
231
- end
232
- expect(widget.versions.last.whodunnit).to eq(new_name)
233
- end
234
-
235
- it "should revert the value of `PaperTrail.whodunnit` to it's previous value after executing the block" do
236
- widget.whodunnit(new_name) { |w| w.update_attributes(:name => 'Elizabeth') }
237
- expect(PaperTrail.whodunnit).to eq(orig_name)
238
- end
239
-
240
- context "error within block" do
241
- it "should ensure that the whodunnit value still reverts to it's previous value" do
242
- expect { widget.whodunnit(new_name) { raise } }.to raise_error
243
- expect(PaperTrail.whodunnit).to eq(orig_name)
244
- end
245
- end
246
- end
247
- end
248
-
249
- describe '#touch_with_version' do
250
- it { is_expected.to respond_to(:touch_with_version) }
251
-
252
- it "creates a version" do
253
- count = widget.versions.size
254
- widget.touch_with_version
255
- expect(widget.versions.size).to eq(count + 1)
256
- end
257
-
258
- it "increments the `:updated_at` timestamp" do
259
- time_was = widget.updated_at
260
- widget.touch_with_version
261
- expect(widget.updated_at).to be > time_was
262
- end
263
- end
264
- end
265
-
266
- describe "Class" do
267
- subject { Widget }
268
-
269
- describe "#paper_trail_enabled_for_model?" do
270
- it { is_expected.to respond_to(:paper_trail_enabled_for_model?) }
271
-
272
- it { expect(subject.paper_trail_enabled_for_model?).to be true }
273
- end
274
-
275
- describe '#paper_trail_off!' do
276
- it { is_expected.to respond_to(:paper_trail_off!) }
277
-
278
- it 'should set the `paper_trail_enabled_for_model?` to `false`' do
279
- expect(subject.paper_trail_enabled_for_model?).to be true
280
- subject.paper_trail_off!
281
- expect(subject.paper_trail_enabled_for_model?).to be false
282
- end
283
- end
284
-
285
- describe '#paper_trail_on!' do
286
- before { subject.paper_trail_off! }
287
-
288
- it { is_expected.to respond_to(:paper_trail_on!) }
289
-
290
- it 'should set the `paper_trail_enabled_for_model?` to `true`' do
291
- expect(subject.paper_trail_enabled_for_model?).to be false
292
- subject.paper_trail_on!
293
- expect(subject.paper_trail_enabled_for_model?).to be true
294
- end
295
- end
296
- end
297
- end
298
- end