paper_trail 7.0.2 → 7.0.3
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.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +1 -1
- data/.rubocop_todo.yml +10 -0
- data/.travis.yml +4 -4
- data/Appraisals +3 -5
- data/CHANGELOG.md +16 -1
- data/README.md +70 -119
- data/Rakefile +6 -1
- data/doc/bug_report_template.rb +4 -2
- data/doc/warning_about_not_setting_whodunnit.md +6 -5
- data/gemfiles/ar_4.0.gemfile +1 -1
- data/gemfiles/ar_4.2.gemfile +1 -1
- data/gemfiles/ar_5.0.gemfile +2 -3
- data/gemfiles/ar_5.1.gemfile +8 -0
- data/gemfiles/ar_master.gemfile +2 -2
- data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb.erb +1 -1
- data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb.erb +1 -1
- data/lib/generators/paper_trail/templates/create_version_associations.rb.erb +1 -1
- data/lib/paper_trail/model_config.rb +4 -4
- data/lib/paper_trail/version_concern.rb +4 -4
- data/lib/paper_trail/version_number.rb +1 -1
- data/paper_trail.gemspec +5 -5
- data/spec/controllers/articles_controller_spec.rb +1 -1
- data/spec/generators/install_generator_spec.rb +2 -2
- data/spec/models/animal_spec.rb +5 -5
- data/spec/models/boolit_spec.rb +2 -2
- data/spec/models/callback_modifier_spec.rb +2 -2
- data/spec/models/car_spec.rb +2 -2
- data/spec/models/custom_primary_key_record_spec.rb +2 -2
- data/spec/models/document_spec.rb +2 -2
- data/spec/models/gadget_spec.rb +2 -2
- data/spec/models/joined_version_spec.rb +1 -1
- data/spec/models/json_version_spec.rb +4 -4
- data/spec/models/kitchen/banana_spec.rb +2 -2
- data/spec/models/not_on_update_spec.rb +2 -2
- data/spec/models/post_with_status_spec.rb +4 -4
- data/spec/models/skipper_spec.rb +1 -1
- data/spec/models/thing_spec.rb +2 -2
- data/spec/models/vehicle_spec.rb +2 -2
- data/spec/models/version_spec.rb +26 -5
- data/spec/models/widget_spec.rb +10 -2
- data/spec/modules/paper_trail_spec.rb +2 -2
- data/spec/modules/version_concern_spec.rb +2 -2
- data/spec/modules/version_number_spec.rb +1 -1
- data/spec/paper_trail/associations_spec.rb +965 -0
- data/spec/paper_trail/cleaner_spec.rb +2 -2
- data/spec/paper_trail/config_spec.rb +2 -2
- data/spec/paper_trail/model_spec.rb +1421 -0
- data/spec/paper_trail/serializer_spec.rb +85 -0
- data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +1 -1
- data/spec/paper_trail/serializers/json_spec.rb +2 -2
- data/spec/paper_trail/serializers/yaml_spec.rb +42 -0
- data/spec/paper_trail/version_limit_spec.rb +2 -2
- data/spec/paper_trail/version_spec.rb +96 -0
- data/spec/paper_trail_spec.rb +1 -1
- data/spec/requests/articles_spec.rb +2 -2
- data/spec/spec_helper.rb +47 -79
- data/{test → spec/support}/custom_json_serializer.rb +0 -0
- data/test/dummy/app/models/document.rb +1 -1
- data/test/dummy/app/models/not_on_update.rb +1 -1
- data/test/dummy/app/models/widget.rb +1 -1
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +18 -9
- data/test/dummy/db/schema.rb +64 -64
- data/test/test_helper.rb +1 -33
- data/test/unit/serializers/mixin_json_test.rb +1 -1
- metadata +27 -32
- data/spec/models/truck_spec.rb +0 -5
- data/spec/rails_helper.rb +0 -34
- data/test/time_travel_helper.rb +0 -1
- data/test/unit/associations_test.rb +0 -1032
- data/test/unit/model_test.rb +0 -1416
- data/test/unit/serializer_test.rb +0 -107
- data/test/unit/serializers/yaml_test.rb +0 -50
- data/test/unit/version_test.rb +0 -112
data/test/unit/model_test.rb
DELETED
@@ -1,1416 +0,0 @@
|
|
1
|
-
require "test_helper"
|
2
|
-
require "time_travel_helper"
|
3
|
-
|
4
|
-
class HasPaperTrailModelTest < ActiveSupport::TestCase
|
5
|
-
context "A record with defined 'only' and 'ignore' attributes" do
|
6
|
-
setup { @article = Article.create }
|
7
|
-
|
8
|
-
should "creation should change the number of versions" do
|
9
|
-
assert_equal(1, PaperTrail::Version.count)
|
10
|
-
end
|
11
|
-
|
12
|
-
context "which updates an ignored column" do
|
13
|
-
should "not change the number of versions" do
|
14
|
-
@article.update_attributes title: "My first title"
|
15
|
-
assert_equal(1, PaperTrail::Version.count)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
context "which updates an ignored column with truly Proc" do
|
20
|
-
should "not change the number of versions" do
|
21
|
-
@article.update_attributes abstract: "ignore abstract"
|
22
|
-
assert_equal(1, PaperTrail::Version.count)
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
context "which updates an ignored column with falsy Proc" do
|
27
|
-
should "change the number of versions" do
|
28
|
-
@article.update_attributes abstract: "do not ignore abstract!"
|
29
|
-
assert_equal(2, PaperTrail::Version.count)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
context "which updates an ignored column, ignored with truly Proc and a selected column" do
|
34
|
-
setup do
|
35
|
-
@article.update_attributes(
|
36
|
-
title: "My first title",
|
37
|
-
content: "Some text here.",
|
38
|
-
abstract: "ignore abstract"
|
39
|
-
)
|
40
|
-
end
|
41
|
-
|
42
|
-
should "change the number of versions" do
|
43
|
-
assert_equal(2, PaperTrail::Version.count)
|
44
|
-
end
|
45
|
-
|
46
|
-
should "show the new version in the model's `versions` association" do
|
47
|
-
assert_equal(2, @article.versions.size)
|
48
|
-
end
|
49
|
-
|
50
|
-
should "have stored only non-ignored attributes" do
|
51
|
-
expected = { "content" => [nil, "Some text here."] }
|
52
|
-
assert_equal expected, @article.versions.last.changeset
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
context "which updates an ignored column, ignored with falsy Proc and a selected column" do
|
57
|
-
setup do
|
58
|
-
@article.update_attributes(
|
59
|
-
title: "My first title",
|
60
|
-
content: "Some text here.",
|
61
|
-
abstract: "do not ignore abstract"
|
62
|
-
)
|
63
|
-
end
|
64
|
-
|
65
|
-
should "change the number of versions" do
|
66
|
-
assert_equal(2, PaperTrail::Version.count)
|
67
|
-
end
|
68
|
-
|
69
|
-
should "show the new version in the model's `versions` association" do
|
70
|
-
assert_equal(2, @article.versions.size)
|
71
|
-
end
|
72
|
-
|
73
|
-
should "have stored only non-ignored attributes" do
|
74
|
-
expected = {
|
75
|
-
"content" => [nil, "Some text here."],
|
76
|
-
"abstract" => [nil, "do not ignore abstract"]
|
77
|
-
}
|
78
|
-
assert_equal expected, @article.versions.last.changeset
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
context "which updates a selected column" do
|
83
|
-
setup { @article.update_attributes content: "Some text here." }
|
84
|
-
should "change the number of versions" do
|
85
|
-
assert_equal(2, PaperTrail::Version.count)
|
86
|
-
end
|
87
|
-
|
88
|
-
should "show the new version in the model's `versions` association" do
|
89
|
-
assert_equal(2, @article.versions.size)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
context "which updates a non-ignored and non-selected column" do
|
94
|
-
should "not change the number of versions" do
|
95
|
-
@article.update_attributes abstract: "Other abstract"
|
96
|
-
assert_equal(1, PaperTrail::Version.count)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
context "which updates a skipped column" do
|
101
|
-
should "not change the number of versions" do
|
102
|
-
@article.update_attributes file_upload: "Your data goes here"
|
103
|
-
assert_equal(1, PaperTrail::Version.count)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
context "which updates a skipped column and a selected column" do
|
108
|
-
setup do
|
109
|
-
@article.update_attributes(
|
110
|
-
file_upload: "Your data goes here",
|
111
|
-
content: "Some text here."
|
112
|
-
)
|
113
|
-
end
|
114
|
-
|
115
|
-
should "change the number of versions" do
|
116
|
-
assert_equal(2, PaperTrail::Version.count)
|
117
|
-
end
|
118
|
-
|
119
|
-
should "show the new version in the model's `versions` association" do
|
120
|
-
assert_equal(2, @article.versions.size)
|
121
|
-
end
|
122
|
-
|
123
|
-
should "have stored only non-skipped attributes" do
|
124
|
-
assert_equal ({ "content" => [nil, "Some text here."] }),
|
125
|
-
@article.versions.last.changeset
|
126
|
-
end
|
127
|
-
|
128
|
-
context "and when updated again" do
|
129
|
-
setup do
|
130
|
-
@article.update_attributes(
|
131
|
-
file_upload: "More data goes here",
|
132
|
-
content: "More text here."
|
133
|
-
)
|
134
|
-
@old_article = @article.versions.last
|
135
|
-
end
|
136
|
-
|
137
|
-
should "have removed the skipped attributes when saving the previous version" do
|
138
|
-
assert_nil PaperTrail.serializer.load(@old_article.object)["file_upload"]
|
139
|
-
end
|
140
|
-
|
141
|
-
should "have kept the non-skipped attributes in the previous version" do
|
142
|
-
assert_equal "Some text here.", PaperTrail.serializer.load(@old_article.object)["content"]
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
|
147
|
-
context "which gets destroyed" do
|
148
|
-
setup { @article.destroy }
|
149
|
-
should "change the number of versions" do assert_equal(2, PaperTrail::Version.count) end
|
150
|
-
|
151
|
-
should "show the new version in the model's `versions` association" do
|
152
|
-
assert_equal(2, @article.versions.size)
|
153
|
-
end
|
154
|
-
end
|
155
|
-
end
|
156
|
-
|
157
|
-
context "A record with defined 'ignore' attribute" do
|
158
|
-
setup { @legacy_widget = LegacyWidget.create }
|
159
|
-
|
160
|
-
context "which updates an ignored column" do
|
161
|
-
setup { @legacy_widget.update_attributes version: 1 }
|
162
|
-
should "not change the number of versions" do assert_equal(1, PaperTrail::Version.count) end
|
163
|
-
end
|
164
|
-
end
|
165
|
-
|
166
|
-
context 'A record with defined "if" and "unless" attributes' do
|
167
|
-
setup { @translation = Translation.new headline: "Headline" }
|
168
|
-
|
169
|
-
context "for non-US translations" do
|
170
|
-
setup { @translation.save }
|
171
|
-
should "not change the number of versions" do assert_equal(0, PaperTrail::Version.count) end
|
172
|
-
|
173
|
-
context "after update" do
|
174
|
-
setup { @translation.update_attributes content: "Content" }
|
175
|
-
should "not change the number of versions" do assert_equal(0, PaperTrail::Version.count) end
|
176
|
-
end
|
177
|
-
|
178
|
-
context "after destroy" do
|
179
|
-
setup { @translation.destroy }
|
180
|
-
should "not change the number of versions" do assert_equal(0, PaperTrail::Version.count) end
|
181
|
-
end
|
182
|
-
end
|
183
|
-
|
184
|
-
context "for US translations" do
|
185
|
-
setup { @translation.language_code = "US" }
|
186
|
-
|
187
|
-
context "that are drafts" do
|
188
|
-
setup do
|
189
|
-
@translation.type = "DRAFT"
|
190
|
-
@translation.save
|
191
|
-
end
|
192
|
-
|
193
|
-
should "not change the number of versions" do
|
194
|
-
assert_equal(0, PaperTrail::Version.count)
|
195
|
-
end
|
196
|
-
|
197
|
-
context "after update" do
|
198
|
-
setup { @translation.update_attributes content: "Content" }
|
199
|
-
should "not change the number of versions" do
|
200
|
-
assert_equal(0, PaperTrail::Version.count)
|
201
|
-
end
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
context "that are not drafts" do
|
206
|
-
setup { @translation.save }
|
207
|
-
|
208
|
-
should "change the number of versions" do
|
209
|
-
assert_equal(1, PaperTrail::Version.count)
|
210
|
-
end
|
211
|
-
|
212
|
-
context "after update" do
|
213
|
-
setup { @translation.update_attributes content: "Content" }
|
214
|
-
should "change the number of versions" do
|
215
|
-
assert_equal(2, PaperTrail::Version.count)
|
216
|
-
end
|
217
|
-
|
218
|
-
should "show the new version in the model's `versions` association" do
|
219
|
-
assert_equal(2, @translation.versions.size)
|
220
|
-
end
|
221
|
-
end
|
222
|
-
|
223
|
-
context "after destroy" do
|
224
|
-
setup { @translation.destroy }
|
225
|
-
should "change the number of versions" do
|
226
|
-
assert_equal(2, PaperTrail::Version.count)
|
227
|
-
end
|
228
|
-
|
229
|
-
should "show the new version in the model's `versions` association" do
|
230
|
-
assert_equal(2, @translation.versions.size)
|
231
|
-
end
|
232
|
-
end
|
233
|
-
end
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
context "A new record" do
|
238
|
-
setup { @widget = Widget.new }
|
239
|
-
|
240
|
-
should "not have any previous versions" do
|
241
|
-
assert_equal [], @widget.versions
|
242
|
-
end
|
243
|
-
|
244
|
-
should "be live" do
|
245
|
-
assert @widget.paper_trail.live?
|
246
|
-
end
|
247
|
-
|
248
|
-
context "which is then created" do
|
249
|
-
setup { @widget.update_attributes name: "Henry", created_at: Time.now - 1.day }
|
250
|
-
|
251
|
-
should "have one previous version" do
|
252
|
-
assert_equal 1, @widget.versions.length
|
253
|
-
end
|
254
|
-
|
255
|
-
should "be nil in its previous version" do
|
256
|
-
assert_nil @widget.versions.first.object
|
257
|
-
assert_nil @widget.versions.first.reify
|
258
|
-
end
|
259
|
-
|
260
|
-
should "record the correct event" do
|
261
|
-
assert_match(/create/i, @widget.versions.first.event)
|
262
|
-
end
|
263
|
-
|
264
|
-
should "be live" do
|
265
|
-
assert @widget.paper_trail.live?
|
266
|
-
end
|
267
|
-
|
268
|
-
should "use the widget `updated_at` as the version's `created_at`" do
|
269
|
-
assert_equal @widget.updated_at.to_i, @widget.versions.first.created_at.to_i
|
270
|
-
end
|
271
|
-
|
272
|
-
should "have changes" do
|
273
|
-
# TODO: Postgres does not appear to pass back
|
274
|
-
# ActiveSupport::TimeWithZone, so choosing the lowest common denominator
|
275
|
-
# to test.
|
276
|
-
|
277
|
-
changes = {
|
278
|
-
"name" => [nil, "Henry"],
|
279
|
-
"created_at" => [nil, @widget.created_at.to_time.utc],
|
280
|
-
"updated_at" => [nil, @widget.updated_at.to_time.utc],
|
281
|
-
"id" => [nil, @widget.id]
|
282
|
-
}
|
283
|
-
|
284
|
-
assert_kind_of Time, @widget.versions.last.changeset["updated_at"][1]
|
285
|
-
assert_changes_equal changes, @widget.versions.last.changeset
|
286
|
-
end
|
287
|
-
|
288
|
-
context "and then updated without any changes" do
|
289
|
-
setup { @widget.touch }
|
290
|
-
|
291
|
-
should "not have a new version" do
|
292
|
-
assert_equal 1, @widget.versions.length
|
293
|
-
end
|
294
|
-
end
|
295
|
-
|
296
|
-
context "and then updated with changes" do
|
297
|
-
setup { @widget.update_attributes name: "Harry" }
|
298
|
-
|
299
|
-
should "have two previous versions" do
|
300
|
-
assert_equal 2, @widget.versions.length
|
301
|
-
end
|
302
|
-
|
303
|
-
should "be available in its previous version" do
|
304
|
-
assert_equal "Harry", @widget.name
|
305
|
-
assert_not_nil @widget.versions.last.object
|
306
|
-
widget = @widget.versions.last.reify
|
307
|
-
assert_equal "Henry", widget.name
|
308
|
-
assert_equal "Harry", @widget.name
|
309
|
-
end
|
310
|
-
|
311
|
-
should "have the same ID in its previous version" do
|
312
|
-
assert_equal @widget.id, @widget.versions.last.reify.id
|
313
|
-
end
|
314
|
-
|
315
|
-
should "record the correct event" do
|
316
|
-
assert_match(/update/i, @widget.versions.last.event)
|
317
|
-
end
|
318
|
-
|
319
|
-
should "have versions that are not live" do
|
320
|
-
assert(@widget.versions.map(&:reify).compact.all? { |w| !w.paper_trail.live? })
|
321
|
-
end
|
322
|
-
|
323
|
-
should "have stored changes" do
|
324
|
-
# Behavior for ActiveRecord 4 is different than ActiveRecord 3;
|
325
|
-
# AR4 includes the `updated_at` column in changes for updates, which
|
326
|
-
# is why we reject it from the right side of this assertion.
|
327
|
-
last_obj_changes = @widget.versions.last.object_changes
|
328
|
-
actual = PaperTrail.serializer.load(last_obj_changes).reject { |k, _v|
|
329
|
-
k.to_sym == :updated_at
|
330
|
-
}
|
331
|
-
assert_equal ({ "name" => %w(Henry Harry) }), actual
|
332
|
-
actual = @widget.versions.last.changeset.reject { |k, _v|
|
333
|
-
k.to_sym == :updated_at
|
334
|
-
}
|
335
|
-
assert_equal ({ "name" => %w(Henry Harry) }), actual
|
336
|
-
end
|
337
|
-
|
338
|
-
should "return changes with indifferent access" do
|
339
|
-
assert_equal %w(Henry Harry), @widget.versions.last.changeset[:name]
|
340
|
-
assert_equal %w(Henry Harry), @widget.versions.last.changeset["name"]
|
341
|
-
end
|
342
|
-
|
343
|
-
context "and has one associated object" do
|
344
|
-
setup do
|
345
|
-
@wotsit = @widget.create_wotsit name: "John"
|
346
|
-
end
|
347
|
-
|
348
|
-
should "not copy the has_one association by default when reifying" do
|
349
|
-
reified_widget = @widget.versions.last.reify
|
350
|
-
# association hasn't been affected by reifying
|
351
|
-
assert_equal @wotsit, reified_widget.wotsit
|
352
|
-
# confirm that the association is correct
|
353
|
-
assert_equal @wotsit, @widget.reload.wotsit
|
354
|
-
end
|
355
|
-
|
356
|
-
should "copy the has_one association when reifying with :has_one => true" do
|
357
|
-
reified_widget = @widget.versions.last.reify(has_one: true)
|
358
|
-
# wotsit wasn't there at the last version
|
359
|
-
assert_nil reified_widget.wotsit
|
360
|
-
# wotsit should still exist on live object
|
361
|
-
assert_equal @wotsit, @widget.reload.wotsit
|
362
|
-
end
|
363
|
-
end
|
364
|
-
|
365
|
-
context "and has many associated objects" do
|
366
|
-
setup do
|
367
|
-
@f0 = @widget.fluxors.create name: "f-zero"
|
368
|
-
@f1 = @widget.fluxors.create name: "f-one"
|
369
|
-
@reified_widget = @widget.versions.last.reify
|
370
|
-
end
|
371
|
-
|
372
|
-
should "copy the has_many associations when reifying" do
|
373
|
-
assert_equal @widget.fluxors.length, @reified_widget.fluxors.length
|
374
|
-
assert_same_elements @widget.fluxors, @reified_widget.fluxors
|
375
|
-
|
376
|
-
assert_equal @widget.versions.length, @reified_widget.versions.length
|
377
|
-
assert_same_elements @widget.versions, @reified_widget.versions
|
378
|
-
end
|
379
|
-
end
|
380
|
-
|
381
|
-
context "and has many associated polymorphic objects" do
|
382
|
-
setup do
|
383
|
-
@f0 = @widget.whatchamajiggers.create name: "f-zero"
|
384
|
-
@f1 = @widget.whatchamajiggers.create name: "f-zero"
|
385
|
-
@reified_widget = @widget.versions.last.reify
|
386
|
-
end
|
387
|
-
|
388
|
-
should "copy the has_many associations when reifying" do
|
389
|
-
assert_equal @widget.whatchamajiggers.length, @reified_widget.whatchamajiggers.length
|
390
|
-
assert_same_elements @widget.whatchamajiggers, @reified_widget.whatchamajiggers
|
391
|
-
|
392
|
-
assert_equal @widget.versions.length, @reified_widget.versions.length
|
393
|
-
assert_same_elements @widget.versions, @reified_widget.versions
|
394
|
-
end
|
395
|
-
end
|
396
|
-
|
397
|
-
context "polymorphic objects by themselves" do
|
398
|
-
setup do
|
399
|
-
@widget = Whatchamajigger.new name: "f-zero"
|
400
|
-
end
|
401
|
-
|
402
|
-
should "not fail with a nil pointer on the polymorphic association" do
|
403
|
-
@widget.save!
|
404
|
-
end
|
405
|
-
end
|
406
|
-
|
407
|
-
context "and then destroyed" do
|
408
|
-
setup do
|
409
|
-
@fluxor = @widget.fluxors.create name: "flux"
|
410
|
-
@widget.destroy
|
411
|
-
@reified_widget = PaperTrail::Version.last.reify
|
412
|
-
end
|
413
|
-
|
414
|
-
should "record the correct event" do
|
415
|
-
assert_match(/destroy/i, PaperTrail::Version.last.event)
|
416
|
-
end
|
417
|
-
|
418
|
-
should "have three previous versions" do
|
419
|
-
assert_equal 3, PaperTrail::Version.with_item_keys("Widget", @widget.id).length
|
420
|
-
end
|
421
|
-
|
422
|
-
should "be available in its previous version" do
|
423
|
-
assert_equal @widget.id, @reified_widget.id
|
424
|
-
assert_attributes_equal @widget.attributes, @reified_widget.attributes
|
425
|
-
end
|
426
|
-
|
427
|
-
should "be re-creatable from its previous version" do
|
428
|
-
assert @reified_widget.save
|
429
|
-
end
|
430
|
-
|
431
|
-
should "restore its associations on its previous version" do
|
432
|
-
@reified_widget.save
|
433
|
-
assert_equal 1, @reified_widget.fluxors.length
|
434
|
-
end
|
435
|
-
|
436
|
-
should "have nil item for last version" do
|
437
|
-
assert_nil(@widget.versions.last.item)
|
438
|
-
end
|
439
|
-
|
440
|
-
should "not have changes" do
|
441
|
-
assert_equal({}, @widget.versions.last.changeset)
|
442
|
-
end
|
443
|
-
end
|
444
|
-
end
|
445
|
-
end
|
446
|
-
end
|
447
|
-
|
448
|
-
# Test the serialisation and deserialisation.
|
449
|
-
# TODO: binary
|
450
|
-
context "A record's papertrail" do
|
451
|
-
setup do
|
452
|
-
@date_time = DateTime.now.utc
|
453
|
-
@time = Time.now
|
454
|
-
@date = Date.new 2009, 5, 29
|
455
|
-
@widget = Widget.create(
|
456
|
-
name: "Warble",
|
457
|
-
a_text: "The quick brown fox",
|
458
|
-
an_integer: 42,
|
459
|
-
a_float: 153.01,
|
460
|
-
a_decimal: 2.71828,
|
461
|
-
a_datetime: @date_time,
|
462
|
-
a_time: @time,
|
463
|
-
a_date: @date,
|
464
|
-
a_boolean: true
|
465
|
-
)
|
466
|
-
@widget.update_attributes(
|
467
|
-
name: nil,
|
468
|
-
a_text: nil,
|
469
|
-
an_integer: nil,
|
470
|
-
a_float: nil,
|
471
|
-
a_decimal: nil,
|
472
|
-
a_datetime: nil,
|
473
|
-
a_time: nil,
|
474
|
-
a_date: nil,
|
475
|
-
a_boolean: false
|
476
|
-
)
|
477
|
-
@previous = @widget.versions.last.reify
|
478
|
-
end
|
479
|
-
|
480
|
-
should "handle strings" do
|
481
|
-
assert_equal "Warble", @previous.name
|
482
|
-
end
|
483
|
-
|
484
|
-
should "handle text" do
|
485
|
-
assert_equal "The quick brown fox", @previous.a_text
|
486
|
-
end
|
487
|
-
|
488
|
-
should "handle integers" do
|
489
|
-
assert_equal 42, @previous.an_integer
|
490
|
-
end
|
491
|
-
|
492
|
-
should "handle floats" do
|
493
|
-
assert_in_delta 153.01, @previous.a_float, 0.001
|
494
|
-
end
|
495
|
-
|
496
|
-
should "handle decimals" do
|
497
|
-
assert_in_delta 2.7183, @previous.a_decimal, 0.0001
|
498
|
-
end
|
499
|
-
|
500
|
-
should "handle datetimes" do
|
501
|
-
assert_equal @date_time.to_time.utc.to_i, @previous.a_datetime.to_time.utc.to_i
|
502
|
-
end
|
503
|
-
|
504
|
-
should "handle times" do
|
505
|
-
assert_equal @time.utc.to_i, @previous.a_time.utc.to_i
|
506
|
-
end
|
507
|
-
|
508
|
-
should "handle dates" do
|
509
|
-
assert_equal @date, @previous.a_date
|
510
|
-
end
|
511
|
-
|
512
|
-
should "handle booleans" do
|
513
|
-
assert @previous.a_boolean
|
514
|
-
end
|
515
|
-
|
516
|
-
context "after a column is removed from the record's schema" do
|
517
|
-
setup do
|
518
|
-
@last = @widget.versions.last
|
519
|
-
end
|
520
|
-
|
521
|
-
should "reify previous version" do
|
522
|
-
assert_kind_of Widget, @last.reify
|
523
|
-
end
|
524
|
-
|
525
|
-
should "restore all forward-compatible attributes" do
|
526
|
-
assert_equal "Warble", @last.reify.name
|
527
|
-
assert_equal "The quick brown fox", @last.reify.a_text
|
528
|
-
assert_equal 42, @last.reify.an_integer
|
529
|
-
assert_in_delta 153.01, @last.reify.a_float, 0.001
|
530
|
-
assert_in_delta 2.7183, @last.reify.a_decimal, 0.0001
|
531
|
-
assert_equal @date_time.to_time.utc.to_i, @last.reify.a_datetime.to_time.utc.to_i
|
532
|
-
assert_equal @time.utc.to_i, @last.reify.a_time.utc.to_i
|
533
|
-
assert_equal @date, @last.reify.a_date
|
534
|
-
assert @last.reify.a_boolean
|
535
|
-
end
|
536
|
-
end
|
537
|
-
end
|
538
|
-
|
539
|
-
context "A record" do
|
540
|
-
setup { @widget = Widget.create name: "Zaphod" }
|
541
|
-
|
542
|
-
context "with PaperTrail globally disabled" do
|
543
|
-
setup do
|
544
|
-
PaperTrail.enabled = false
|
545
|
-
@count = @widget.versions.length
|
546
|
-
end
|
547
|
-
|
548
|
-
teardown { PaperTrail.enabled = true }
|
549
|
-
|
550
|
-
context "when updated" do
|
551
|
-
setup { @widget.update_attributes name: "Beeblebrox" }
|
552
|
-
|
553
|
-
should "not add to its trail" do
|
554
|
-
assert_equal @count, @widget.versions.length
|
555
|
-
end
|
556
|
-
end
|
557
|
-
end
|
558
|
-
|
559
|
-
context "with its paper trail turned off" do
|
560
|
-
setup do
|
561
|
-
Widget.paper_trail.disable
|
562
|
-
@count = @widget.versions.length
|
563
|
-
end
|
564
|
-
|
565
|
-
teardown { Widget.paper_trail.enable }
|
566
|
-
|
567
|
-
context "when updated" do
|
568
|
-
setup { @widget.update_attributes name: "Beeblebrox" }
|
569
|
-
|
570
|
-
should "not add to its trail" do
|
571
|
-
assert_equal @count, @widget.versions.length
|
572
|
-
end
|
573
|
-
end
|
574
|
-
|
575
|
-
context 'when destroyed "without versioning"' do
|
576
|
-
should "leave paper trail off after call" do
|
577
|
-
@widget.paper_trail.without_versioning :destroy
|
578
|
-
assert_equal false, Widget.paper_trail.enabled?
|
579
|
-
end
|
580
|
-
end
|
581
|
-
|
582
|
-
context "and then its paper trail turned on" do
|
583
|
-
setup { Widget.paper_trail.enable }
|
584
|
-
|
585
|
-
context "when updated" do
|
586
|
-
setup { @widget.update_attributes name: "Ford" }
|
587
|
-
|
588
|
-
should "add to its trail" do
|
589
|
-
assert_equal @count + 1, @widget.versions.length
|
590
|
-
end
|
591
|
-
end
|
592
|
-
|
593
|
-
context 'when updated "without versioning"' do
|
594
|
-
setup do
|
595
|
-
@widget.paper_trail.without_versioning do
|
596
|
-
@widget.update_attributes name: "Ford"
|
597
|
-
end
|
598
|
-
# The model instance should yield itself for convenience purposes
|
599
|
-
@widget.paper_trail.without_versioning { |w| w.update_attributes name: "Nixon" }
|
600
|
-
end
|
601
|
-
|
602
|
-
should "not create new version" do
|
603
|
-
assert_equal @count, @widget.versions.length
|
604
|
-
end
|
605
|
-
|
606
|
-
should "enable paper trail after call" do
|
607
|
-
assert Widget.paper_trail.enabled?
|
608
|
-
end
|
609
|
-
end
|
610
|
-
|
611
|
-
context "when receiving a method name as an argument" do
|
612
|
-
setup { @widget.paper_trail.without_versioning(:touch_with_version) }
|
613
|
-
|
614
|
-
should "not create new version" do
|
615
|
-
assert_equal @count, @widget.versions.length
|
616
|
-
end
|
617
|
-
|
618
|
-
should "enable paper trail after call" do
|
619
|
-
assert Widget.paper_trail.enabled?
|
620
|
-
end
|
621
|
-
end
|
622
|
-
end
|
623
|
-
end
|
624
|
-
end
|
625
|
-
|
626
|
-
context "A papertrail with somebody making changes" do
|
627
|
-
setup do
|
628
|
-
@widget = Widget.new name: "Fidget"
|
629
|
-
end
|
630
|
-
|
631
|
-
context "when a record is created" do
|
632
|
-
setup do
|
633
|
-
PaperTrail.whodunnit = "Alice"
|
634
|
-
@widget.save
|
635
|
-
@version = @widget.versions.last # only 1 version
|
636
|
-
end
|
637
|
-
|
638
|
-
should "track who made the change" do
|
639
|
-
assert_equal "Alice", @version.whodunnit
|
640
|
-
assert_nil @version.paper_trail_originator
|
641
|
-
assert_equal "Alice", @version.terminator
|
642
|
-
assert_equal "Alice", @widget.paper_trail.originator
|
643
|
-
end
|
644
|
-
|
645
|
-
context "when a record is updated" do
|
646
|
-
setup do
|
647
|
-
PaperTrail.whodunnit = "Bob"
|
648
|
-
@widget.update_attributes name: "Rivet"
|
649
|
-
@version = @widget.versions.last
|
650
|
-
end
|
651
|
-
|
652
|
-
should "track who made the change" do
|
653
|
-
assert_equal "Bob", @version.whodunnit
|
654
|
-
assert_equal "Alice", @version.paper_trail_originator
|
655
|
-
assert_equal "Bob", @version.terminator
|
656
|
-
assert_equal "Bob", @widget.paper_trail.originator
|
657
|
-
end
|
658
|
-
|
659
|
-
context "when a record is destroyed" do
|
660
|
-
setup do
|
661
|
-
PaperTrail.whodunnit = "Charlie"
|
662
|
-
@widget.destroy
|
663
|
-
@version = PaperTrail::Version.last
|
664
|
-
end
|
665
|
-
|
666
|
-
should "track who made the change" do
|
667
|
-
assert_equal "Charlie", @version.whodunnit
|
668
|
-
assert_equal "Bob", @version.paper_trail_originator
|
669
|
-
assert_equal "Charlie", @version.terminator
|
670
|
-
assert_equal "Charlie", @widget.paper_trail.originator
|
671
|
-
end
|
672
|
-
end
|
673
|
-
end
|
674
|
-
end
|
675
|
-
end
|
676
|
-
|
677
|
-
test "update_attributes! records timestamps" do
|
678
|
-
wotsit = Wotsit.create! name: "wotsit"
|
679
|
-
wotsit.update_attributes! name: "changed"
|
680
|
-
reified = wotsit.versions.last.reify
|
681
|
-
assert_not_nil reified.created_at
|
682
|
-
assert_not_nil reified.updated_at
|
683
|
-
end
|
684
|
-
|
685
|
-
# Tests that it doesn't try to write created_on as an attribute just because
|
686
|
-
# a created_on method exists.
|
687
|
-
#
|
688
|
-
# - ActiveModel::MissingAttributeError in Rails 4
|
689
|
-
#
|
690
|
-
test "update_attributes! does not raise error" do
|
691
|
-
wotsit = Wotsit.create! name: "name1"
|
692
|
-
assert_nothing_raised { wotsit.update_attributes! name: "name2" }
|
693
|
-
end
|
694
|
-
|
695
|
-
context "A subclass" do
|
696
|
-
setup do
|
697
|
-
@foo = FooWidget.create
|
698
|
-
@foo.update_attributes! name: "Foo"
|
699
|
-
end
|
700
|
-
|
701
|
-
should "reify with the correct type" do
|
702
|
-
# For some reason this test appears to be broken on AR4 in the test env.
|
703
|
-
# Executing it manually in the Rails console seems to work.. not sure what
|
704
|
-
# the issues is here.
|
705
|
-
assert_kind_of FooWidget, @foo.versions.last.reify if ActiveRecord::VERSION::MAJOR < 4
|
706
|
-
assert_equal @foo.versions.first, PaperTrail::Version.last.previous
|
707
|
-
assert_nil PaperTrail::Version.last.next
|
708
|
-
end
|
709
|
-
|
710
|
-
should "should return the correct originator" do
|
711
|
-
PaperTrail.whodunnit = "Ben"
|
712
|
-
@foo.update_attribute(:name, "Geoffrey")
|
713
|
-
assert_equal PaperTrail.whodunnit, @foo.paper_trail.originator
|
714
|
-
end
|
715
|
-
|
716
|
-
context "when destroyed" do
|
717
|
-
setup { @foo.destroy }
|
718
|
-
|
719
|
-
should "reify with the correct type" do
|
720
|
-
assert_kind_of FooWidget, @foo.versions.last.reify
|
721
|
-
assert_equal @foo.versions[1], PaperTrail::Version.last.previous
|
722
|
-
assert_nil PaperTrail::Version.last.next
|
723
|
-
end
|
724
|
-
end
|
725
|
-
end
|
726
|
-
|
727
|
-
context "An item with versions" do
|
728
|
-
setup do
|
729
|
-
@widget = Widget.create name: "Widget"
|
730
|
-
@widget.update_attributes name: "Fidget"
|
731
|
-
@widget.update_attributes name: "Digit"
|
732
|
-
end
|
733
|
-
|
734
|
-
context "which were created over time" do
|
735
|
-
setup do
|
736
|
-
@created = 2.days.ago
|
737
|
-
@first_update = 1.day.ago
|
738
|
-
@second_update = 1.hour.ago
|
739
|
-
@widget.versions[0].update_attributes created_at: @created
|
740
|
-
@widget.versions[1].update_attributes created_at: @first_update
|
741
|
-
@widget.versions[2].update_attributes created_at: @second_update
|
742
|
-
@widget.update_attribute :updated_at, @second_update
|
743
|
-
end
|
744
|
-
|
745
|
-
should "return nil for version_at before it was created" do
|
746
|
-
assert_nil @widget.paper_trail.version_at(@created - 1)
|
747
|
-
end
|
748
|
-
|
749
|
-
should "return how it looked when created for version_at its creation" do
|
750
|
-
assert_equal "Widget", @widget.paper_trail.version_at(@created).name
|
751
|
-
end
|
752
|
-
|
753
|
-
should "return how it looked before its first update" do
|
754
|
-
assert_equal "Widget", @widget.paper_trail.version_at(@first_update - 1).name
|
755
|
-
end
|
756
|
-
|
757
|
-
should "return how it looked after its first update" do
|
758
|
-
assert_equal "Fidget", @widget.paper_trail.version_at(@first_update).name
|
759
|
-
end
|
760
|
-
|
761
|
-
should "return how it looked before its second update" do
|
762
|
-
assert_equal "Fidget", @widget.paper_trail.version_at(@second_update - 1).name
|
763
|
-
end
|
764
|
-
|
765
|
-
should "return how it looked after its second update" do
|
766
|
-
assert_equal "Digit", @widget.paper_trail.version_at(@second_update).name
|
767
|
-
end
|
768
|
-
|
769
|
-
should "return the current object for version_at after latest update" do
|
770
|
-
assert_equal "Digit", @widget.paper_trail.version_at(1.day.from_now).name
|
771
|
-
end
|
772
|
-
|
773
|
-
context "passing in a string representation of a timestamp" do
|
774
|
-
should "still return a widget when appropriate" do
|
775
|
-
# need to add 1 second onto the timestamps before casting to a string,
|
776
|
-
# since casting a Time to a string drops the microseconds
|
777
|
-
assert_equal "Widget",
|
778
|
-
@widget.paper_trail.version_at((@created + 1.second).to_s).name
|
779
|
-
assert_equal "Fidget",
|
780
|
-
@widget.paper_trail.version_at((@first_update + 1.second).to_s).name
|
781
|
-
assert_equal "Digit",
|
782
|
-
@widget.paper_trail.version_at((@second_update + 1.second).to_s).name
|
783
|
-
end
|
784
|
-
end
|
785
|
-
end
|
786
|
-
|
787
|
-
context ".versions_between" do
|
788
|
-
setup do
|
789
|
-
@created = 30.days.ago
|
790
|
-
@first_update = 15.days.ago
|
791
|
-
@second_update = 1.day.ago
|
792
|
-
@widget.versions[0].update_attributes created_at: @created
|
793
|
-
@widget.versions[1].update_attributes created_at: @first_update
|
794
|
-
@widget.versions[2].update_attributes created_at: @second_update
|
795
|
-
@widget.update_attribute :updated_at, @second_update
|
796
|
-
end
|
797
|
-
|
798
|
-
should "return versions in the time period" do
|
799
|
-
assert_equal ["Fidget"],
|
800
|
-
@widget.paper_trail.versions_between(20.days.ago, 10.days.ago).map(&:name)
|
801
|
-
assert_equal %w(Widget Fidget),
|
802
|
-
@widget.paper_trail.versions_between(45.days.ago, 10.days.ago).map(&:name)
|
803
|
-
assert_equal %w(Fidget Digit Digit),
|
804
|
-
@widget.paper_trail.versions_between(16.days.ago, 1.minute.ago).map(&:name)
|
805
|
-
assert_equal [],
|
806
|
-
@widget.paper_trail.versions_between(60.days.ago, 45.days.ago).map(&:name)
|
807
|
-
end
|
808
|
-
end
|
809
|
-
|
810
|
-
context "on the first version" do
|
811
|
-
setup { @version = @widget.versions.first }
|
812
|
-
|
813
|
-
should "have a nil previous version" do
|
814
|
-
assert_nil @version.previous
|
815
|
-
end
|
816
|
-
|
817
|
-
should "return the next version" do
|
818
|
-
assert_equal @widget.versions[1], @version.next
|
819
|
-
end
|
820
|
-
|
821
|
-
should "return the correct index" do
|
822
|
-
assert_equal 0, @version.index
|
823
|
-
end
|
824
|
-
end
|
825
|
-
|
826
|
-
context "on the last version" do
|
827
|
-
setup { @version = @widget.versions.last }
|
828
|
-
|
829
|
-
should "return the previous version" do
|
830
|
-
assert_equal @widget.versions[@widget.versions.length - 2], @version.previous
|
831
|
-
end
|
832
|
-
|
833
|
-
should "have a nil next version" do
|
834
|
-
assert_nil @version.next
|
835
|
-
end
|
836
|
-
|
837
|
-
should "return the correct index" do
|
838
|
-
assert_equal @widget.versions.length - 1, @version.index
|
839
|
-
end
|
840
|
-
end
|
841
|
-
end
|
842
|
-
|
843
|
-
context "An item" do
|
844
|
-
setup do
|
845
|
-
@initial_title = "Foobar"
|
846
|
-
@article = Article.new title: @initial_title
|
847
|
-
end
|
848
|
-
|
849
|
-
context "which is created" do
|
850
|
-
setup { @article.save }
|
851
|
-
|
852
|
-
should "store fixed meta data" do
|
853
|
-
assert_equal 42, @article.versions.last.answer
|
854
|
-
end
|
855
|
-
|
856
|
-
should "store dynamic meta data which is independent of the item" do
|
857
|
-
assert_equal "31 + 11 = 42", @article.versions.last.question
|
858
|
-
end
|
859
|
-
|
860
|
-
should "store dynamic meta data which depends on the item" do
|
861
|
-
assert_equal @article.id, @article.versions.last.article_id
|
862
|
-
end
|
863
|
-
|
864
|
-
should "store dynamic meta data based on a method of the item" do
|
865
|
-
assert_equal @article.action_data_provider_method, @article.versions.last.action
|
866
|
-
end
|
867
|
-
|
868
|
-
should "store dynamic meta data based on an attribute of the item at creation" do
|
869
|
-
assert_equal @initial_title, @article.versions.last.title
|
870
|
-
end
|
871
|
-
|
872
|
-
context "and updated" do
|
873
|
-
setup do
|
874
|
-
@article.update_attributes! content: "Better text.", title: "Rhubarb"
|
875
|
-
end
|
876
|
-
|
877
|
-
should "store fixed meta data" do
|
878
|
-
assert_equal 42, @article.versions.last.answer
|
879
|
-
end
|
880
|
-
|
881
|
-
should "store dynamic meta data which is independent of the item" do
|
882
|
-
assert_equal "31 + 11 = 42", @article.versions.last.question
|
883
|
-
end
|
884
|
-
|
885
|
-
should "store dynamic meta data which depends on the item" do
|
886
|
-
assert_equal @article.id, @article.versions.last.article_id
|
887
|
-
end
|
888
|
-
|
889
|
-
should "store dynamic meta data based on an attribute of the item prior to the update" do
|
890
|
-
assert_equal @initial_title, @article.versions.last.title
|
891
|
-
end
|
892
|
-
end
|
893
|
-
|
894
|
-
context "and destroyed" do
|
895
|
-
setup { @article.destroy }
|
896
|
-
|
897
|
-
should "store fixed metadata" do
|
898
|
-
assert_equal 42, @article.versions.last.answer
|
899
|
-
end
|
900
|
-
|
901
|
-
should "store dynamic metadata which is independent of the item" do
|
902
|
-
assert_equal "31 + 11 = 42", @article.versions.last.question
|
903
|
-
end
|
904
|
-
|
905
|
-
should "store dynamic metadata which depends on the item" do
|
906
|
-
assert_equal @article.id, @article.versions.last.article_id
|
907
|
-
end
|
908
|
-
|
909
|
-
should "store dynamic metadata based on attribute of item prior to destruction" do
|
910
|
-
assert_equal @initial_title, @article.versions.last.title
|
911
|
-
end
|
912
|
-
end
|
913
|
-
end
|
914
|
-
end
|
915
|
-
|
916
|
-
context "A reified item" do
|
917
|
-
setup do
|
918
|
-
widget = Widget.create name: "Bob"
|
919
|
-
%w(Tom Dick Jane).each { |name| widget.update_attributes name: name }
|
920
|
-
@version = widget.versions.last
|
921
|
-
@widget = @version.reify
|
922
|
-
end
|
923
|
-
|
924
|
-
should "know which version it came from" do
|
925
|
-
assert_equal @version, @widget.version
|
926
|
-
end
|
927
|
-
|
928
|
-
should "return its previous self" do
|
929
|
-
assert_equal @widget.versions[-2].reify,
|
930
|
-
@widget.paper_trail.previous_version
|
931
|
-
end
|
932
|
-
end
|
933
|
-
|
934
|
-
context "A non-reified item" do
|
935
|
-
setup { @widget = Widget.new }
|
936
|
-
|
937
|
-
should "not have a previous version" do
|
938
|
-
assert_nil @widget.paper_trail.previous_version
|
939
|
-
end
|
940
|
-
|
941
|
-
should "not have a next version" do
|
942
|
-
assert_nil @widget.paper_trail.next_version
|
943
|
-
end
|
944
|
-
|
945
|
-
context "with versions" do
|
946
|
-
setup do
|
947
|
-
@widget.save
|
948
|
-
%w(Tom Dick Jane).each { |name| @widget.update_attributes name: name }
|
949
|
-
end
|
950
|
-
|
951
|
-
should "have a previous version" do
|
952
|
-
assert_equal @widget.versions.last.reify.name,
|
953
|
-
@widget.paper_trail.previous_version.name
|
954
|
-
end
|
955
|
-
|
956
|
-
should "not have a next version" do
|
957
|
-
assert_nil @widget.paper_trail.next_version
|
958
|
-
end
|
959
|
-
end
|
960
|
-
end
|
961
|
-
|
962
|
-
context "A reified item" do
|
963
|
-
setup do
|
964
|
-
@widget = Widget.create name: "Bob"
|
965
|
-
%w(Tom Dick Jane).each { |name| @widget.update_attributes name: name }
|
966
|
-
@second_widget = @widget.versions[1].reify # first widget is `nil`
|
967
|
-
@last_widget = @widget.versions.last.reify
|
968
|
-
end
|
969
|
-
|
970
|
-
should "have a previous version" do
|
971
|
-
# `create` events return `nil` for `reify`
|
972
|
-
assert_nil @second_widget.paper_trail.previous_version
|
973
|
-
assert_equal @widget.versions[-2].reify.name,
|
974
|
-
@last_widget.paper_trail.previous_version.name
|
975
|
-
end
|
976
|
-
|
977
|
-
should "have a next version" do
|
978
|
-
assert_equal @widget.versions[2].reify.name, @second_widget.paper_trail.next_version.name
|
979
|
-
assert_equal @last_widget.paper_trail.next_version.name, @widget.name
|
980
|
-
end
|
981
|
-
end
|
982
|
-
|
983
|
-
context ":has_many :through" do
|
984
|
-
setup do
|
985
|
-
@book = Book.create title: "War and Peace"
|
986
|
-
@dostoyevsky = Person.create name: "Dostoyevsky"
|
987
|
-
@solzhenitsyn = Person.create name: "Solzhenitsyn"
|
988
|
-
end
|
989
|
-
|
990
|
-
should "store version on source <<" do
|
991
|
-
count = PaperTrail::Version.count
|
992
|
-
@book.authors << @dostoyevsky
|
993
|
-
assert_equal 1, PaperTrail::Version.count - count
|
994
|
-
assert_equal PaperTrail::Version.last, @book.authorships.first.versions.first
|
995
|
-
end
|
996
|
-
|
997
|
-
should "store version on source create" do
|
998
|
-
count = PaperTrail::Version.count
|
999
|
-
@book.authors.create name: "Tolstoy"
|
1000
|
-
assert_equal 2, PaperTrail::Version.count - count
|
1001
|
-
actual = [
|
1002
|
-
PaperTrail::Version.order(:id).to_a[-2].item,
|
1003
|
-
PaperTrail::Version.last.item
|
1004
|
-
]
|
1005
|
-
assert_same_elements [Person.last, Authorship.last], actual
|
1006
|
-
end
|
1007
|
-
|
1008
|
-
should "store version on join destroy" do
|
1009
|
-
@book.authors << @dostoyevsky
|
1010
|
-
count = PaperTrail::Version.count
|
1011
|
-
@book.authorships.reload.last.destroy
|
1012
|
-
assert_equal 1, PaperTrail::Version.count - count
|
1013
|
-
assert_equal @book, PaperTrail::Version.last.reify.book
|
1014
|
-
assert_equal @dostoyevsky, PaperTrail::Version.last.reify.author
|
1015
|
-
end
|
1016
|
-
|
1017
|
-
should "store version on join clear" do
|
1018
|
-
@book.authors << @dostoyevsky
|
1019
|
-
count = PaperTrail::Version.count
|
1020
|
-
@book.authorships.reload.destroy_all
|
1021
|
-
assert_equal 1, PaperTrail::Version.count - count
|
1022
|
-
assert_equal @book, PaperTrail::Version.last.reify.book
|
1023
|
-
assert_equal @dostoyevsky, PaperTrail::Version.last.reify.author
|
1024
|
-
end
|
1025
|
-
end
|
1026
|
-
|
1027
|
-
context "When an attribute has a custom serializer" do
|
1028
|
-
setup do
|
1029
|
-
@person = Person.new(time_zone: "Samoa")
|
1030
|
-
end
|
1031
|
-
|
1032
|
-
should "be an instance of ActiveSupport::TimeZone" do
|
1033
|
-
assert_equal ActiveSupport::TimeZone, @person.time_zone.class
|
1034
|
-
end
|
1035
|
-
|
1036
|
-
context "when the model is saved" do
|
1037
|
-
setup do
|
1038
|
-
@changes_before_save = @person.changes.dup
|
1039
|
-
@person.save!
|
1040
|
-
end
|
1041
|
-
|
1042
|
-
# Test for serialization:
|
1043
|
-
should "version.object_changes should store long serialization of TimeZone object" do
|
1044
|
-
len = @person.versions.last.object_changes.length
|
1045
|
-
assert len < 105, "object_changes length was #{len}"
|
1046
|
-
end
|
1047
|
-
|
1048
|
-
# It should store the serialized value.
|
1049
|
-
should "version.object_changes attribute should have stored the value from serializer" do
|
1050
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
1051
|
-
YAML.load(@person.versions.last.object_changes)
|
1052
|
-
]
|
1053
|
-
assert_equal [nil, "Samoa"], as_stored_in_version[:time_zone]
|
1054
|
-
serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
|
1055
|
-
assert_equal serialized_value, as_stored_in_version[:time_zone].last
|
1056
|
-
end
|
1057
|
-
|
1058
|
-
# Tests for unserialization:
|
1059
|
-
should "version.changeset should convert attribute to original, unserialized value" do
|
1060
|
-
unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
|
1061
|
-
assert_equal unserialized_value,
|
1062
|
-
@person.versions.last.changeset[:time_zone].last
|
1063
|
-
end
|
1064
|
-
|
1065
|
-
should "record.changes (before save) returns the original, unserialized values" do
|
1066
|
-
assert_equal [NilClass, ActiveSupport::TimeZone],
|
1067
|
-
@changes_before_save[:time_zone].map(&:class)
|
1068
|
-
end
|
1069
|
-
|
1070
|
-
should "version.changeset should be the same as record.changes was before the save" do
|
1071
|
-
actual = @person.versions.last.changeset.delete_if { |k, _v| k.to_sym == :id }
|
1072
|
-
assert_equal @changes_before_save, actual
|
1073
|
-
actual = @person.versions.last.changeset[:time_zone].map(&:class)
|
1074
|
-
assert_equal [NilClass, ActiveSupport::TimeZone], actual
|
1075
|
-
end
|
1076
|
-
|
1077
|
-
context "when that attribute is updated" do
|
1078
|
-
setup do
|
1079
|
-
@attribute_value_before_change = @person.time_zone
|
1080
|
-
@person.assign_attributes(time_zone: "Pacific Time (US & Canada)")
|
1081
|
-
@changes_before_save = @person.changes.dup
|
1082
|
-
@person.save!
|
1083
|
-
end
|
1084
|
-
|
1085
|
-
# Tests for serialization
|
1086
|
-
# -----------------------
|
1087
|
-
#
|
1088
|
-
# Before the serialized attributes fix, the object/object_changes value
|
1089
|
-
# that was stored was ridiculously long (58723).
|
1090
|
-
#
|
1091
|
-
# version.object should not have stored the default, ridiculously long
|
1092
|
-
# (to_yaml) serialization of the TimeZone object.
|
1093
|
-
should "object should not store long serialization of TimeZone object" do
|
1094
|
-
len = @person.versions.last.object.length
|
1095
|
-
assert len < 105, "object length was #{len}"
|
1096
|
-
end
|
1097
|
-
|
1098
|
-
# Need an additional clause to detect what version of ActiveRecord is
|
1099
|
-
# being used for this test because AR4 injects the `updated_at` column
|
1100
|
-
# into the changeset for updates to models.
|
1101
|
-
#
|
1102
|
-
# version.object_changes should not have stored the default,
|
1103
|
-
# ridiculously long (to_yaml) serialization of the TimeZone object
|
1104
|
-
should "object_changes should not store long serialization of TimeZone object" do
|
1105
|
-
max_len = ActiveRecord::VERSION::MAJOR < 4 ? 105 : 118
|
1106
|
-
len = @person.versions.last.object_changes.length
|
1107
|
-
assert len < max_len, "object_changes length was #{len}"
|
1108
|
-
end
|
1109
|
-
|
1110
|
-
# But now it stores the short, serialized value.
|
1111
|
-
should "version.object attribute should have stored value from serializer" do
|
1112
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
1113
|
-
YAML.load(@person.versions.last.object)
|
1114
|
-
]
|
1115
|
-
assert_equal "Samoa", as_stored_in_version[:time_zone]
|
1116
|
-
serialized_value = Person::TimeZoneSerializer.dump(@attribute_value_before_change)
|
1117
|
-
assert_equal serialized_value, as_stored_in_version[:time_zone]
|
1118
|
-
end
|
1119
|
-
|
1120
|
-
should "version.object_changes attribute should have stored value from serializer" do
|
1121
|
-
as_stored_in_version = HashWithIndifferentAccess[
|
1122
|
-
YAML.load(@person.versions.last.object_changes)
|
1123
|
-
]
|
1124
|
-
assert_equal ["Samoa", "Pacific Time (US & Canada)"], as_stored_in_version[:time_zone]
|
1125
|
-
serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
|
1126
|
-
assert_equal serialized_value, as_stored_in_version[:time_zone].last
|
1127
|
-
end
|
1128
|
-
|
1129
|
-
# Tests for unserialization:
|
1130
|
-
should "version.reify should convert attribute to original, unserialized value" do
|
1131
|
-
unserialized_value = Person::TimeZoneSerializer.load(@attribute_value_before_change)
|
1132
|
-
assert_equal unserialized_value,
|
1133
|
-
@person.versions.last.reify.time_zone
|
1134
|
-
end
|
1135
|
-
|
1136
|
-
should "version.changeset should convert attribute to original, unserialized value" do
|
1137
|
-
unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
|
1138
|
-
assert_equal unserialized_value,
|
1139
|
-
@person.versions.last.changeset[:time_zone].last
|
1140
|
-
end
|
1141
|
-
|
1142
|
-
should "record.changes (before save) returns the original, unserialized values" do
|
1143
|
-
assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone],
|
1144
|
-
@changes_before_save[:time_zone].map(&:class)
|
1145
|
-
end
|
1146
|
-
|
1147
|
-
should "version.changeset should be the same as record.changes was before the save" do
|
1148
|
-
assert_equal @changes_before_save, @person.versions.last.changeset
|
1149
|
-
assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone],
|
1150
|
-
@person.versions.last.changeset[:time_zone].map(&:class)
|
1151
|
-
end
|
1152
|
-
end
|
1153
|
-
end
|
1154
|
-
end
|
1155
|
-
|
1156
|
-
context "A new model instance which uses a custom PaperTrail::Version class" do
|
1157
|
-
setup { @post = Post.new }
|
1158
|
-
|
1159
|
-
context "which is then saved" do
|
1160
|
-
setup { @post.save }
|
1161
|
-
should "change the number of post versions" do assert_equal 1, PostVersion.count end
|
1162
|
-
should "not change the number of versions" do assert_equal(0, PaperTrail::Version.count) end
|
1163
|
-
end
|
1164
|
-
end
|
1165
|
-
|
1166
|
-
context "An existing model instance which uses a custom PaperTrail::Version class" do
|
1167
|
-
setup { @post = Post.create }
|
1168
|
-
should "have one post version" do assert_equal(1, PostVersion.count) end
|
1169
|
-
|
1170
|
-
context "on the first version" do
|
1171
|
-
setup { @version = @post.versions.first }
|
1172
|
-
|
1173
|
-
should "have the correct index" do
|
1174
|
-
assert_equal 0, @version.index
|
1175
|
-
end
|
1176
|
-
end
|
1177
|
-
|
1178
|
-
should "have versions of the custom class" do
|
1179
|
-
assert_equal "PostVersion", @post.versions.first.class.name
|
1180
|
-
end
|
1181
|
-
|
1182
|
-
context "which is modified" do
|
1183
|
-
setup do
|
1184
|
-
@post.update_attributes(content: "Some new content")
|
1185
|
-
end
|
1186
|
-
|
1187
|
-
should "change the number of post versions" do
|
1188
|
-
assert_equal(2, PostVersion.count)
|
1189
|
-
end
|
1190
|
-
|
1191
|
-
should "not change the number of versions" do
|
1192
|
-
assert_equal(0, PaperTrail::Version.count)
|
1193
|
-
end
|
1194
|
-
|
1195
|
-
should "not have stored changes when object_changes column doesn't exist" do
|
1196
|
-
assert_nil @post.versions.last.changeset
|
1197
|
-
end
|
1198
|
-
end
|
1199
|
-
end
|
1200
|
-
|
1201
|
-
context "An overwritten default accessor" do
|
1202
|
-
setup do
|
1203
|
-
@song = Song.create length: 4
|
1204
|
-
@song.update_attributes length: 5
|
1205
|
-
end
|
1206
|
-
|
1207
|
-
should 'return "overwritten" value on live instance' do
|
1208
|
-
assert_equal 5, @song.length
|
1209
|
-
end
|
1210
|
-
should 'return "overwritten" value on reified instance' do
|
1211
|
-
assert_equal 4, @song.versions.last.reify.length
|
1212
|
-
end
|
1213
|
-
|
1214
|
-
context "Has a virtual attribute injected into the ActiveModel::Dirty changes" do
|
1215
|
-
setup do
|
1216
|
-
@song.name = "Good Vibrations"
|
1217
|
-
@song.save
|
1218
|
-
@song.name = "Yellow Submarine"
|
1219
|
-
end
|
1220
|
-
|
1221
|
-
should "return persist the changes on the live instance properly" do
|
1222
|
-
assert_equal "Yellow Submarine", @song.name
|
1223
|
-
end
|
1224
|
-
should 'return "overwritten" virtual attribute on the reified instance' do
|
1225
|
-
assert_equal "Good Vibrations", @song.versions.last.reify.name
|
1226
|
-
end
|
1227
|
-
end
|
1228
|
-
end
|
1229
|
-
|
1230
|
-
context "An unsaved record" do
|
1231
|
-
setup do
|
1232
|
-
@widget = Widget.new
|
1233
|
-
@widget.destroy
|
1234
|
-
end
|
1235
|
-
should "not have a version created on destroy" do
|
1236
|
-
assert @widget.versions.empty?
|
1237
|
-
end
|
1238
|
-
end
|
1239
|
-
|
1240
|
-
context "A model with a custom association" do
|
1241
|
-
setup do
|
1242
|
-
@doc = Document.create
|
1243
|
-
@doc.update_attributes name: "Doc 1"
|
1244
|
-
end
|
1245
|
-
|
1246
|
-
should "not respond to versions method" do
|
1247
|
-
assert !@doc.respond_to?(:versions)
|
1248
|
-
end
|
1249
|
-
|
1250
|
-
should "create a new version record" do
|
1251
|
-
assert_equal 2, @doc.paper_trail_versions.length
|
1252
|
-
end
|
1253
|
-
|
1254
|
-
should "respond to `next_version` as normal" do
|
1255
|
-
reified = @doc.paper_trail_versions.last.reify
|
1256
|
-
assert_equal reified.paper_trail.next_version.name, @doc.name
|
1257
|
-
end
|
1258
|
-
|
1259
|
-
should "respond to `previous_version` as normal" do
|
1260
|
-
@doc.update_attributes name: "Doc 2"
|
1261
|
-
assert_equal 3, @doc.paper_trail_versions.length
|
1262
|
-
assert_equal "Doc 1", @doc.paper_trail.previous_version.name
|
1263
|
-
end
|
1264
|
-
end
|
1265
|
-
|
1266
|
-
context "The `on` option" do
|
1267
|
-
context "on create" do
|
1268
|
-
should "only have a version for the create event" do
|
1269
|
-
record = ::On::Create.create(name: "Alice")
|
1270
|
-
record.update_attributes name: "blah"
|
1271
|
-
record.destroy
|
1272
|
-
assert_equal 1, record.versions.length
|
1273
|
-
assert_equal "create", record.versions.last.event
|
1274
|
-
end
|
1275
|
-
end
|
1276
|
-
|
1277
|
-
context "on update" do
|
1278
|
-
should "only have a version for the update event" do
|
1279
|
-
record = ::On::Update.create(name: "Alice")
|
1280
|
-
record.update_attributes name: "blah"
|
1281
|
-
record.destroy
|
1282
|
-
assert_equal 1, record.versions.length
|
1283
|
-
assert_equal "update", record.versions.last.event
|
1284
|
-
end
|
1285
|
-
end
|
1286
|
-
|
1287
|
-
context "on destroy" do
|
1288
|
-
should "only have a version for the destroy event" do
|
1289
|
-
record = ::On::Destroy.create(name: "Alice")
|
1290
|
-
record.update_attributes name: "blah"
|
1291
|
-
record.destroy
|
1292
|
-
assert_equal 1, record.versions.length
|
1293
|
-
assert_equal "destroy", record.versions.last.event
|
1294
|
-
end
|
1295
|
-
end
|
1296
|
-
|
1297
|
-
context "on []" do
|
1298
|
-
setup do
|
1299
|
-
@record = ::On::EmptyArray.create(name: "Alice")
|
1300
|
-
@record.update_attributes name: "blah"
|
1301
|
-
end
|
1302
|
-
|
1303
|
-
teardown do
|
1304
|
-
@record.destroy
|
1305
|
-
end
|
1306
|
-
|
1307
|
-
should "not have any versions" do
|
1308
|
-
assert_equal 0, @record.versions.length
|
1309
|
-
end
|
1310
|
-
|
1311
|
-
should "still respond to touch_with_version" do
|
1312
|
-
@record.paper_trail.touch_with_version
|
1313
|
-
assert_equal 1, @record.versions.length
|
1314
|
-
end
|
1315
|
-
end
|
1316
|
-
|
1317
|
-
context "allows a symbol to be passed" do
|
1318
|
-
should "only have a version for hte create event" do
|
1319
|
-
record = ::On::Create.create(name: "Alice")
|
1320
|
-
record.update_attributes name: "blah"
|
1321
|
-
record.destroy
|
1322
|
-
assert_equal 1, record.versions.length
|
1323
|
-
assert_equal "create", record.versions.last.event
|
1324
|
-
end
|
1325
|
-
end
|
1326
|
-
end
|
1327
|
-
|
1328
|
-
context "A model with column version and custom version_method" do
|
1329
|
-
setup do
|
1330
|
-
@legacy_widget = LegacyWidget.create(name: "foo", version: 2)
|
1331
|
-
end
|
1332
|
-
|
1333
|
-
should "set version on create" do
|
1334
|
-
assert_equal 2, @legacy_widget.version
|
1335
|
-
end
|
1336
|
-
|
1337
|
-
should "allow version updates" do
|
1338
|
-
@legacy_widget.update_attributes version: 3
|
1339
|
-
assert_equal 3, @legacy_widget.version
|
1340
|
-
end
|
1341
|
-
|
1342
|
-
should "create a new version record" do
|
1343
|
-
assert_equal 1, @legacy_widget.versions.size
|
1344
|
-
end
|
1345
|
-
end
|
1346
|
-
|
1347
|
-
context "A reified item with a column -version- and custom version_method" do
|
1348
|
-
setup do
|
1349
|
-
widget = LegacyWidget.create(name: "foo", version: 2)
|
1350
|
-
%w(bar baz).each { |name| widget.update_attributes name: name }
|
1351
|
-
@version = widget.versions.last
|
1352
|
-
@widget = @version.reify
|
1353
|
-
end
|
1354
|
-
|
1355
|
-
should "know which version it came from" do
|
1356
|
-
assert_equal @version, @widget.custom_version
|
1357
|
-
end
|
1358
|
-
|
1359
|
-
should "return its previous self" do
|
1360
|
-
assert_equal @widget.versions[-2].reify, @widget.paper_trail.previous_version
|
1361
|
-
end
|
1362
|
-
end
|
1363
|
-
|
1364
|
-
context "custom events" do
|
1365
|
-
context "on create" do
|
1366
|
-
should "only have a version for the created event" do
|
1367
|
-
record = ::On::Create.new.tap { |model|
|
1368
|
-
model.paper_trail_event = "created"
|
1369
|
-
}
|
1370
|
-
record.update_attributes name: "blah"
|
1371
|
-
record.destroy
|
1372
|
-
assert_equal 1, record.versions.length
|
1373
|
-
assert_equal "created", record.versions.last.event
|
1374
|
-
end
|
1375
|
-
end
|
1376
|
-
|
1377
|
-
context "on update" do
|
1378
|
-
should "only have a version for the name_updated event" do
|
1379
|
-
record = ::On::Update.create(name: "Alice").tap { |model|
|
1380
|
-
model.paper_trail_event = "name_updated"
|
1381
|
-
}
|
1382
|
-
record.update_attributes name: "blah"
|
1383
|
-
record.destroy
|
1384
|
-
assert_equal 1, record.versions.length
|
1385
|
-
assert_equal "name_updated", record.versions.last.event
|
1386
|
-
end
|
1387
|
-
end
|
1388
|
-
|
1389
|
-
context "on destroy" do
|
1390
|
-
should "only have a version for the destroy event" do
|
1391
|
-
record = ::On::Destroy.create(name: "Alice").tap { |model|
|
1392
|
-
model.paper_trail_event = "destroyed"
|
1393
|
-
}
|
1394
|
-
record.update_attributes name: "blah"
|
1395
|
-
record.destroy
|
1396
|
-
assert_equal 1, record.versions.length
|
1397
|
-
assert_equal "destroyed", record.versions.last.event
|
1398
|
-
end
|
1399
|
-
end
|
1400
|
-
end
|
1401
|
-
|
1402
|
-
context "`PaperTrail::Config.version_limit` set" do
|
1403
|
-
setup do
|
1404
|
-
PaperTrail.config.version_limit = 2
|
1405
|
-
@widget = Widget.create! name: "Henry"
|
1406
|
-
6.times { @widget.update_attribute(:name, FFaker::Lorem.word) }
|
1407
|
-
end
|
1408
|
-
|
1409
|
-
teardown { PaperTrail.config.version_limit = nil }
|
1410
|
-
|
1411
|
-
should "limit the number of versions to 3 (2 plus the created at event)" do
|
1412
|
-
assert_equal "create", @widget.versions.first.event
|
1413
|
-
assert_equal 3, @widget.versions.size
|
1414
|
-
end
|
1415
|
-
end
|
1416
|
-
end
|