paper_trail 7.0.2 → 7.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (75) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CONTRIBUTING.md +1 -1
  3. data/.rubocop_todo.yml +10 -0
  4. data/.travis.yml +4 -4
  5. data/Appraisals +3 -5
  6. data/CHANGELOG.md +16 -1
  7. data/README.md +70 -119
  8. data/Rakefile +6 -1
  9. data/doc/bug_report_template.rb +4 -2
  10. data/doc/warning_about_not_setting_whodunnit.md +6 -5
  11. data/gemfiles/ar_4.0.gemfile +1 -1
  12. data/gemfiles/ar_4.2.gemfile +1 -1
  13. data/gemfiles/ar_5.0.gemfile +2 -3
  14. data/gemfiles/ar_5.1.gemfile +8 -0
  15. data/gemfiles/ar_master.gemfile +2 -2
  16. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb.erb +1 -1
  17. data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb.erb +1 -1
  18. data/lib/generators/paper_trail/templates/create_version_associations.rb.erb +1 -1
  19. data/lib/paper_trail/model_config.rb +4 -4
  20. data/lib/paper_trail/version_concern.rb +4 -4
  21. data/lib/paper_trail/version_number.rb +1 -1
  22. data/paper_trail.gemspec +5 -5
  23. data/spec/controllers/articles_controller_spec.rb +1 -1
  24. data/spec/generators/install_generator_spec.rb +2 -2
  25. data/spec/models/animal_spec.rb +5 -5
  26. data/spec/models/boolit_spec.rb +2 -2
  27. data/spec/models/callback_modifier_spec.rb +2 -2
  28. data/spec/models/car_spec.rb +2 -2
  29. data/spec/models/custom_primary_key_record_spec.rb +2 -2
  30. data/spec/models/document_spec.rb +2 -2
  31. data/spec/models/gadget_spec.rb +2 -2
  32. data/spec/models/joined_version_spec.rb +1 -1
  33. data/spec/models/json_version_spec.rb +4 -4
  34. data/spec/models/kitchen/banana_spec.rb +2 -2
  35. data/spec/models/not_on_update_spec.rb +2 -2
  36. data/spec/models/post_with_status_spec.rb +4 -4
  37. data/spec/models/skipper_spec.rb +1 -1
  38. data/spec/models/thing_spec.rb +2 -2
  39. data/spec/models/vehicle_spec.rb +2 -2
  40. data/spec/models/version_spec.rb +26 -5
  41. data/spec/models/widget_spec.rb +10 -2
  42. data/spec/modules/paper_trail_spec.rb +2 -2
  43. data/spec/modules/version_concern_spec.rb +2 -2
  44. data/spec/modules/version_number_spec.rb +1 -1
  45. data/spec/paper_trail/associations_spec.rb +965 -0
  46. data/spec/paper_trail/cleaner_spec.rb +2 -2
  47. data/spec/paper_trail/config_spec.rb +2 -2
  48. data/spec/paper_trail/model_spec.rb +1421 -0
  49. data/spec/paper_trail/serializer_spec.rb +85 -0
  50. data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +1 -1
  51. data/spec/paper_trail/serializers/json_spec.rb +2 -2
  52. data/spec/paper_trail/serializers/yaml_spec.rb +42 -0
  53. data/spec/paper_trail/version_limit_spec.rb +2 -2
  54. data/spec/paper_trail/version_spec.rb +96 -0
  55. data/spec/paper_trail_spec.rb +1 -1
  56. data/spec/requests/articles_spec.rb +2 -2
  57. data/spec/spec_helper.rb +47 -79
  58. data/{test → spec/support}/custom_json_serializer.rb +0 -0
  59. data/test/dummy/app/models/document.rb +1 -1
  60. data/test/dummy/app/models/not_on_update.rb +1 -1
  61. data/test/dummy/app/models/widget.rb +1 -1
  62. data/test/dummy/config/routes.rb +1 -1
  63. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +18 -9
  64. data/test/dummy/db/schema.rb +64 -64
  65. data/test/test_helper.rb +1 -33
  66. data/test/unit/serializers/mixin_json_test.rb +1 -1
  67. metadata +27 -32
  68. data/spec/models/truck_spec.rb +0 -5
  69. data/spec/rails_helper.rb +0 -34
  70. data/test/time_travel_helper.rb +0 -1
  71. data/test/unit/associations_test.rb +0 -1032
  72. data/test/unit/model_test.rb +0 -1416
  73. data/test/unit/serializer_test.rb +0 -107
  74. data/test/unit/serializers/yaml_test.rb +0 -50
  75. data/test/unit/version_test.rb +0 -112
@@ -1,5 +0,0 @@
1
- require "rails_helper"
2
-
3
- describe Truck, type: :model do
4
- it { is_expected.not_to be_versioned }
5
- end
@@ -1,34 +0,0 @@
1
- # This file is copied to spec/ when you run 'rails generate rspec:install'
2
- ENV["RAILS_ENV"] ||= "test"
3
- ENV["DB"] ||= "sqlite"
4
-
5
- unless File.exist?(File.expand_path("../../test/dummy/config/database.yml", __FILE__))
6
- warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
7
- end
8
-
9
- require "spec_helper"
10
- require File.expand_path("../../test/dummy/config/environment", __FILE__)
11
- require "rspec/rails"
12
- require "paper_trail/frameworks/rspec"
13
- require "ffaker"
14
- require "timecop"
15
-
16
- # prevent Test::Unit's AutoRunner from executing during RSpec's rake task
17
- Test::Unit.run = true if defined?(Test::Unit) && Test::Unit.respond_to?(:run=)
18
-
19
- # Checks for pending migrations before tests are run.
20
- # If you are not using ActiveRecord, you can remove this line.
21
- ActiveRecord::Migration.check_pending! if ActiveRecord::Migration.respond_to?(:check_pending!)
22
-
23
- RSpec.configure do |config|
24
- config.fixture_path = "#{::Rails.root}/spec/fixtures"
25
-
26
- # If you're not using ActiveRecord, or you'd prefer not to run each of your
27
- # examples within a transaction, remove the following line or assign false
28
- # instead of true.
29
- config.use_transactional_fixtures = true
30
-
31
- # The different available types are documented in the features, such as in
32
- # https://relishapp.com/rspec/rspec-rails/docs
33
- # config.infer_spec_type_from_file_location!
34
- end
@@ -1 +0,0 @@
1
- require "timecop"
@@ -1,1032 +0,0 @@
1
- require "test_helper"
2
- require "time_travel_helper"
3
-
4
- class AssociationsTest < ActiveSupport::TestCase
5
- CHAPTER_NAMES = [
6
- "Down the Rabbit-Hole",
7
- "The Pool of Tears",
8
- "A Caucus-Race and a Long Tale",
9
- "The Rabbit Sends in a Little Bill",
10
- "Advice from a Caterpillar",
11
- "Pig and Pepper",
12
- "A Mad Tea-Party",
13
- "The Queen's Croquet-Ground",
14
- "The Mock Turtle's Story",
15
- "The Lobster Quadrille",
16
- "Who Stole the Tarts?",
17
- "Alice's Evidence"
18
- ].freeze
19
-
20
- # These would have been done in test_helper.rb if using_mysql? is true
21
- unless using_mysql?
22
- if respond_to? :use_transactional_tests=
23
- self.use_transactional_tests = false
24
- else
25
- self.use_transactional_fixtures = false
26
- end
27
- setup { DatabaseCleaner.start }
28
- end
29
-
30
- teardown do
31
- Timecop.return
32
- # This would have been done in test_helper.rb if using_mysql? is true
33
- DatabaseCleaner.clean unless using_mysql?
34
- end
35
-
36
- context "a has_one association" do
37
- setup { @widget = Widget.create name: "widget_0" }
38
-
39
- context "before the associated was created" do
40
- setup do
41
- @widget.update_attributes name: "widget_1"
42
- @wotsit = @widget.create_wotsit name: "wotsit_0"
43
- end
44
-
45
- context "when reified" do
46
- setup { @widget0 = @widget.versions.last.reify(has_one: true) }
47
-
48
- should "see the associated as it was at the time" do
49
- assert_nil @widget0.wotsit
50
- end
51
-
52
- should "not persist changes to the live association" do
53
- assert_equal @wotsit, @widget.reload.wotsit
54
- end
55
- end
56
- end
57
-
58
- context "where the association is created between model versions" do
59
- setup do
60
- @wotsit = @widget.create_wotsit name: "wotsit_0"
61
- Timecop.travel 1.second.since
62
- @widget.update_attributes name: "widget_1"
63
- end
64
-
65
- context "when reified" do
66
- setup { @widget0 = @widget.versions.last.reify(has_one: true) }
67
-
68
- should "see the associated as it was at the time" do
69
- assert_equal "wotsit_0", @widget0.wotsit.name
70
- end
71
-
72
- should "not persist changes to the live association" do
73
- assert_equal @wotsit, @widget.reload.wotsit
74
- end
75
- end
76
-
77
- context "and then the associated is updated between model versions" do
78
- setup do
79
- @wotsit.update_attributes name: "wotsit_1"
80
- @wotsit.update_attributes name: "wotsit_2"
81
- Timecop.travel 1.second.since
82
- @widget.update_attributes name: "widget_2"
83
- @wotsit.update_attributes name: "wotsit_3"
84
- end
85
-
86
- context "when reified" do
87
- setup { @widget1 = @widget.versions.last.reify(has_one: true) }
88
-
89
- should "see the associated as it was at the time" do
90
- assert_equal "wotsit_2", @widget1.wotsit.name
91
- end
92
-
93
- should "not persist changes to the live association" do
94
- assert_equal "wotsit_3", @widget.reload.wotsit.name
95
- end
96
- end
97
-
98
- context "when reified opting out of has_one reification" do
99
- setup { @widget1 = @widget.versions.last.reify(has_one: false) }
100
-
101
- should "see the associated as it is live" do
102
- assert_equal "wotsit_3", @widget1.wotsit.name
103
- end
104
- end
105
- end
106
-
107
- context "and then the associated is destroyed" do
108
- setup do
109
- @wotsit.destroy
110
- end
111
-
112
- context "when reify" do
113
- setup { @widget1 = @widget.versions.last.reify(has_one: true) }
114
-
115
- should "see the associated as it was at the time" do
116
- assert_equal @wotsit, @widget1.wotsit
117
- end
118
-
119
- should "not persist changes to the live association" do
120
- assert_nil @widget.reload.wotsit
121
- end
122
- end
123
-
124
- context "and then the model is updated" do
125
- setup do
126
- Timecop.travel 1.second.since
127
- @widget.update_attributes name: "widget_3"
128
- end
129
-
130
- context "when reified" do
131
- setup { @widget2 = @widget.versions.last.reify(has_one: true) }
132
-
133
- should "see the associated as it was at the time" do
134
- assert_nil @widget2.wotsit
135
- end
136
- end
137
- end
138
- end
139
- end
140
- end
141
-
142
- context "a has_many association" do
143
- setup { @customer = Customer.create name: "customer_0" }
144
-
145
- context "updated before the associated was created" do
146
- setup do
147
- @customer.update_attributes! name: "customer_1"
148
- @customer.orders.create! order_date: Date.today
149
- end
150
-
151
- context "when reified" do
152
- setup { @customer0 = @customer.versions.last.reify(has_many: true) }
153
-
154
- should "see the associated as it was at the time" do
155
- assert_equal [], @customer0.orders
156
- end
157
-
158
- should "not persist changes to the live association" do
159
- assert_not_equal [], @customer.orders.reload
160
- end
161
- end
162
-
163
- context "when reified with option mark_for_destruction" do
164
- should "mark the associated for destruction" do
165
- @customer0 = @customer.versions.last.reify(
166
- has_many: true,
167
- mark_for_destruction: true
168
- )
169
- assert_equal [true], @customer0.orders.map(&:marked_for_destruction?)
170
- end
171
- end
172
- end
173
-
174
- context "where the association is created between model versions" do
175
- setup do
176
- @order = @customer.orders.create! order_date: "order_date_0"
177
- Timecop.travel 1.second.since
178
- @customer.update_attributes name: "customer_1"
179
- end
180
-
181
- context "when reified" do
182
- setup { @customer0 = @customer.versions.last.reify(has_many: true) }
183
-
184
- should "see the associated as it was at the time" do
185
- assert_equal ["order_date_0"], @customer0.orders.map(&:order_date)
186
- end
187
- end
188
-
189
- context "and then a nested has_many association is created" do
190
- setup do
191
- @order.line_items.create! product: "product_0"
192
- end
193
-
194
- context "when reified" do
195
- setup { @customer0 = @customer.versions.last.reify(has_many: true) }
196
-
197
- should "see the live version of the nested association" do
198
- assert_equal ["product_0"], @customer0.orders.first.line_items.map(&:product)
199
- end
200
- end
201
- end
202
-
203
- context "and then the associated is updated between model versions" do
204
- setup do
205
- @order.update_attributes order_date: "order_date_1"
206
- @order.update_attributes order_date: "order_date_2"
207
- Timecop.travel 1.second.since
208
- @customer.update_attributes name: "customer_2"
209
- @order.update_attributes order_date: "order_date_3"
210
- end
211
-
212
- context "when reified" do
213
- setup { @customer1 = @customer.versions.last.reify(has_many: true) }
214
-
215
- should "see the associated as it was at the time" do
216
- assert_equal ["order_date_2"], @customer1.orders.map(&:order_date)
217
- end
218
-
219
- should "not persist changes to the live association" do
220
- assert_equal ["order_date_3"], @customer.orders.reload.map(&:order_date)
221
- end
222
- end
223
-
224
- context "when reified opting out of has_many reification" do
225
- setup { @customer1 = @customer.versions.last.reify(has_many: false) }
226
-
227
- should "see the associated as it is live" do
228
- assert_equal ["order_date_3"], @customer1.orders.map(&:order_date)
229
- end
230
- end
231
-
232
- context "and then the associated is destroyed" do
233
- setup do
234
- @order.destroy
235
- end
236
-
237
- context "when reified" do
238
- setup { @customer1 = @customer.versions.last.reify(has_many: true) }
239
-
240
- should "see the associated as it was at the time" do
241
- assert_equal ["order_date_2"], @customer1.orders.map(&:order_date)
242
- end
243
-
244
- should "not persist changes to the live association" do
245
- assert_equal [], @customer.orders.reload
246
- end
247
- end
248
- end
249
- end
250
-
251
- context "and then the associated is destroyed" do
252
- setup do
253
- @order.destroy
254
- end
255
-
256
- context "when reified" do
257
- setup { @customer1 = @customer.versions.last.reify(has_many: true) }
258
-
259
- should "see the associated as it was at the time" do
260
- assert_equal [@order.order_date], @customer1.orders.map(&:order_date)
261
- end
262
-
263
- should "not persist changes to the live association" do
264
- assert_equal [], @customer.orders.reload
265
- end
266
- end
267
- end
268
-
269
- context "and then the associated is destroyed between model versions" do
270
- setup do
271
- @order.destroy
272
- Timecop.travel 1.second.since
273
- @customer.update_attributes name: "customer_2"
274
- end
275
-
276
- context "when reified" do
277
- setup { @customer1 = @customer.versions.last.reify(has_many: true) }
278
-
279
- should "see the associated as it was at the time" do
280
- assert_equal [], @customer1.orders
281
- end
282
- end
283
- end
284
-
285
- context "and then another association is added" do
286
- setup do
287
- @customer.orders.create! order_date: "order_date_1"
288
- end
289
-
290
- context "when reified" do
291
- setup { @customer0 = @customer.versions.last.reify(has_many: true) }
292
-
293
- should "see the associated as it was at the time" do
294
- assert_equal ["order_date_0"], @customer0.orders.map(&:order_date)
295
- end
296
-
297
- should "not persist changes to the live association" do
298
- assert_equal %w(order_date_0 order_date_1),
299
- @customer.orders.reload.map(&:order_date).sort
300
- end
301
- end
302
-
303
- context "when reified with option mark_for_destruction" do
304
- should "mark the newly associated for destruction" do
305
- @customer0 = @customer.versions.last.reify(
306
- has_many: true,
307
- mark_for_destruction: true
308
- )
309
- assert @customer0.
310
- orders.
311
- detect { |o| o.order_date == "order_date_1" }.
312
- marked_for_destruction?
313
- end
314
- end
315
- end
316
- end
317
- end
318
-
319
- context "has_many through associations" do
320
- context "Books, Authors, and Authorships" do
321
- setup { @book = Book.create title: "book_0" }
322
-
323
- context "updated before the associated was created" do
324
- setup do
325
- @book.update_attributes! title: "book_1"
326
- @book.authors.create! name: "author_0"
327
- end
328
-
329
- context "when reified" do
330
- setup { @book0 = @book.versions.last.reify(has_many: true) }
331
-
332
- should "see the associated as it was at the time" do
333
- assert_equal [], @book0.authors
334
- end
335
-
336
- should "not persist changes to the live association" do
337
- assert_equal ["author_0"], @book.authors.reload.map(&:name)
338
- end
339
- end
340
-
341
- context "when reified with option mark_for_destruction" do
342
- setup do
343
- @book0 = @book.versions.last.reify(
344
- has_many: true,
345
- mark_for_destruction: true
346
- )
347
- end
348
-
349
- should "mark the associated for destruction" do
350
- assert_equal [true], @book0.authors.map(&:marked_for_destruction?)
351
- end
352
-
353
- should "mark the associated-through for destruction" do
354
- assert_equal [true], @book0.authorships.map(&:marked_for_destruction?)
355
- end
356
- end
357
- end
358
-
359
- context "updated before it is associated with an existing one" do
360
- setup do
361
- person_existing = Person.create(name: "person_existing")
362
- Timecop.travel 1.second.since
363
- @book.update_attributes! title: "book_1"
364
- @book.authors << person_existing
365
- end
366
-
367
- context "when reified" do
368
- setup do
369
- @book0 = @book.versions.last.reify(has_many: true)
370
- end
371
-
372
- should "see the associated as it was at the time" do
373
- assert_equal [], @book0.authors
374
- end
375
- end
376
-
377
- context "when reified with option mark_for_destruction" do
378
- setup do
379
- @book0 = @book.versions.last.reify(
380
- has_many: true,
381
- mark_for_destruction: true
382
- )
383
- end
384
-
385
- should "not mark the associated for destruction" do
386
- assert_equal [false], @book0.authors.map(&:marked_for_destruction?)
387
- end
388
-
389
- should "mark the associated-through for destruction" do
390
- assert_equal [true], @book0.authorships.map(&:marked_for_destruction?)
391
- end
392
- end
393
- end
394
-
395
- context "where the association is created between model versions" do
396
- setup do
397
- @author = @book.authors.create! name: "author_0"
398
- @person_existing = Person.create(name: "person_existing")
399
- Timecop.travel 1.second.since
400
- @book.update_attributes! title: "book_1"
401
- end
402
-
403
- context "when reified" do
404
- setup { @book0 = @book.versions.last.reify(has_many: true) }
405
-
406
- should "see the associated as it was at the time" do
407
- assert_equal ["author_0"], @book0.authors.map(&:name)
408
- end
409
- end
410
-
411
- context "and then the associated is updated between model versions" do
412
- setup do
413
- @author.update_attributes name: "author_1"
414
- @author.update_attributes name: "author_2"
415
- Timecop.travel 1.second.since
416
- @book.update_attributes title: "book_2"
417
- @author.update_attributes name: "author_3"
418
- end
419
-
420
- context "when reified" do
421
- setup { @book1 = @book.versions.last.reify(has_many: true) }
422
-
423
- should "see the associated as it was at the time" do
424
- assert_equal ["author_2"], @book1.authors.map(&:name)
425
- end
426
-
427
- should "not persist changes to the live association" do
428
- assert_equal ["author_3"], @book.authors.reload.map(&:name)
429
- end
430
- end
431
-
432
- context "when reified opting out of has_many reification" do
433
- setup { @book1 = @book.versions.last.reify(has_many: false) }
434
-
435
- should "see the associated as it is live" do
436
- assert_equal ["author_3"], @book1.authors.map(&:name)
437
- end
438
- end
439
- end
440
-
441
- context "and then the associated is destroyed" do
442
- setup do
443
- @author.destroy
444
- end
445
-
446
- context "when reified" do
447
- setup { @book1 = @book.versions.last.reify(has_many: true) }
448
-
449
- should "see the associated as it was at the time" do
450
- assert_equal [@author.name], @book1.authors.map(&:name)
451
- end
452
-
453
- should "not persist changes to the live association" do
454
- assert_equal [], @book.authors.reload
455
- end
456
- end
457
- end
458
-
459
- context "and then the associated is destroyed between model versions" do
460
- setup do
461
- @author.destroy
462
- Timecop.travel 1.second.since
463
- @book.update_attributes title: "book_2"
464
- end
465
-
466
- context "when reified" do
467
- setup { @book1 = @book.versions.last.reify(has_many: true) }
468
-
469
- should "see the associated as it was at the time" do
470
- assert_equal [], @book1.authors
471
- end
472
- end
473
- end
474
-
475
- context "and then the associated is dissociated between model versions" do
476
- setup do
477
- @book.authors = []
478
- Timecop.travel 1.second.since
479
- @book.update_attributes title: "book_2"
480
- end
481
-
482
- context "when reified" do
483
- setup { @book1 = @book.versions.last.reify(has_many: true) }
484
-
485
- should "see the associated as it was at the time" do
486
- assert_equal [], @book1.authors
487
- end
488
- end
489
- end
490
-
491
- context "and then another associated is created" do
492
- setup do
493
- @book.authors.create! name: "author_1"
494
- end
495
-
496
- context "when reified" do
497
- setup { @book0 = @book.versions.last.reify(has_many: true) }
498
-
499
- should "only see the first associated" do
500
- assert_equal ["author_0"], @book0.authors.map(&:name)
501
- end
502
-
503
- should "not persist changes to the live association" do
504
- assert_equal %w(author_0 author_1), @book.authors.reload.map(&:name)
505
- end
506
- end
507
-
508
- context "when reified with option mark_for_destruction" do
509
- setup do
510
- @book0 = @book.versions.last.reify(
511
- has_many: true,
512
- mark_for_destruction: true
513
- )
514
- end
515
-
516
- should "mark the newly associated for destruction" do
517
- assert @book0.
518
- authors.
519
- detect { |a| a.name == "author_1" }.
520
- marked_for_destruction?
521
- end
522
-
523
- should "mark the newly associated-through for destruction" do
524
- assert @book0.
525
- authorships.
526
- detect { |as| as.author.name == "author_1" }.
527
- marked_for_destruction?
528
- end
529
- end
530
- end
531
-
532
- context "and then an existing one is associated" do
533
- setup do
534
- @book.authors << @person_existing
535
- end
536
-
537
- context "when reified" do
538
- setup { @book0 = @book.versions.last.reify(has_many: true) }
539
-
540
- should "only see the first associated" do
541
- assert_equal ["author_0"], @book0.authors.map(&:name)
542
- end
543
-
544
- should "not persist changes to the live association" do
545
- assert_equal %w(author_0 person_existing), @book.authors.reload.map(&:name).sort
546
- end
547
- end
548
-
549
- context "when reified with option mark_for_destruction" do
550
- setup do
551
- @book0 = @book.versions.last.reify(
552
- has_many: true,
553
- mark_for_destruction: true
554
- )
555
- end
556
-
557
- should "not mark the newly associated for destruction" do
558
- assert !@book0.
559
- authors.
560
- detect { |a| a.name == "person_existing" }.
561
- marked_for_destruction?
562
- end
563
-
564
- should "mark the newly associated-through for destruction" do
565
- assert @book0.
566
- authorships.
567
- detect { |as| as.author.name == "person_existing" }.
568
- marked_for_destruction?
569
- end
570
- end
571
- end
572
- end
573
-
574
- context "updated before the associated without paper_trail was created" do
575
- setup do
576
- @book.update_attributes! title: "book_1"
577
- @book.editors.create! name: "editor_0"
578
- end
579
-
580
- context "when reified" do
581
- setup { @book0 = @book.versions.last.reify(has_many: true) }
582
-
583
- should "see the live association" do
584
- assert_equal ["editor_0"], @book0.editors.map(&:name)
585
- end
586
- end
587
- end
588
- end
589
-
590
- context "Chapters, Sections, Paragraphs, Quotations, and Citations" do
591
- setup { @chapter = Chapter.create(name: CHAPTER_NAMES[0]) }
592
-
593
- context "before any associations are created" do
594
- setup do
595
- @chapter.update_attributes(name: CHAPTER_NAMES[1])
596
- end
597
-
598
- should "not reify any associations" do
599
- chapter_v1 = @chapter.versions[1].reify(has_many: true)
600
- assert_equal CHAPTER_NAMES[0], chapter_v1.name
601
- assert_equal [], chapter_v1.sections
602
- assert_equal [], chapter_v1.paragraphs
603
- end
604
- end
605
-
606
- context "after the first has_many through relationship is created" do
607
- setup do
608
- assert_equal 1, @chapter.versions.size
609
- @chapter.update_attributes name: CHAPTER_NAMES[1]
610
- assert_equal 2, @chapter.versions.size
611
-
612
- Timecop.travel 1.second.since
613
- @chapter.sections.create name: "section 1"
614
- Timecop.travel 1.second.since
615
- @chapter.sections.first.update_attributes name: "section 2"
616
- Timecop.travel 1.second.since
617
- @chapter.update_attributes name: CHAPTER_NAMES[2]
618
- assert_equal 3, @chapter.versions.size
619
-
620
- Timecop.travel 1.second.since
621
- @chapter.sections.first.update_attributes name: "section 3"
622
- end
623
-
624
- context "version 1" do
625
- should "have no sections" do
626
- chapter_v1 = @chapter.versions[1].reify(has_many: true)
627
- assert_equal [], chapter_v1.sections
628
- end
629
- end
630
-
631
- context "version 2" do
632
- should "have one section" do
633
- chapter_v2 = @chapter.versions[2].reify(has_many: true)
634
- assert_equal 1, chapter_v2.sections.size
635
-
636
- # Shows the value of the section as it was before
637
- # the chapter was updated.
638
- assert_equal ["section 2"], chapter_v2.sections.map(&:name)
639
-
640
- # Shows the value of the chapter as it was before
641
- assert_equal CHAPTER_NAMES[1], chapter_v2.name
642
- end
643
- end
644
-
645
- context "version 2, before the section was destroyed" do
646
- setup do
647
- @chapter.update_attributes name: CHAPTER_NAMES[2]
648
- Timecop.travel 1.second.since
649
- @chapter.sections.destroy_all
650
- Timecop.travel 1.second.since
651
- end
652
-
653
- should "have the one section" do
654
- chapter_v2 = @chapter.versions[2].reify(has_many: true)
655
- assert_equal ["section 2"], chapter_v2.sections.map(&:name)
656
- end
657
- end
658
-
659
- context "version 3, after the section was destroyed" do
660
- setup do
661
- @chapter.sections.destroy_all
662
- Timecop.travel 1.second.since
663
- @chapter.update_attributes name: CHAPTER_NAMES[3]
664
- Timecop.travel 1.second.since
665
- end
666
-
667
- should "have no sections" do
668
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
669
- assert_equal 0, chapter_v3.sections.size
670
- end
671
- end
672
-
673
- context "after creating a paragraph" do
674
- setup do
675
- assert_equal 3, @chapter.versions.size
676
- @section = @chapter.sections.first
677
- Timecop.travel 1.second.since
678
- @paragraph = @section.paragraphs.create name: "para1"
679
- end
680
-
681
- context "new chapter version" do
682
- should "have one paragraph" do
683
- initial_section_name = @section.name
684
- initial_paragraph_name = @paragraph.name
685
- Timecop.travel 1.second.since
686
- @chapter.update_attributes name: CHAPTER_NAMES[4]
687
- assert_equal 4, @chapter.versions.size
688
- Timecop.travel 1.second.since
689
- @paragraph.update_attributes name: "para3"
690
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
691
- assert_equal [initial_section_name], chapter_v3.sections.map(&:name)
692
- paragraphs = chapter_v3.sections.first.paragraphs
693
- assert_equal 1, paragraphs.size
694
- assert_equal [initial_paragraph_name], paragraphs.map(&:name)
695
- end
696
- end
697
-
698
- context "the version before a section is destroyed" do
699
- should "have the section and paragraph" do
700
- Timecop.travel 1.second.since
701
- @chapter.update_attributes(name: CHAPTER_NAMES[3])
702
- assert_equal 4, @chapter.versions.size
703
- Timecop.travel 1.second.since
704
- @section.destroy
705
- assert_equal 4, @chapter.versions.size
706
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
707
- assert_equal CHAPTER_NAMES[2], chapter_v3.name
708
- assert_equal [@section], chapter_v3.sections
709
- assert_equal [@paragraph], chapter_v3.sections[0].paragraphs
710
- assert_equal [@paragraph], chapter_v3.paragraphs
711
- end
712
- end
713
-
714
- context "the version after a section is destroyed" do
715
- should "not have any sections or paragraphs" do
716
- @section.destroy
717
- Timecop.travel 1.second.since
718
- @chapter.update_attributes(name: CHAPTER_NAMES[5])
719
- assert_equal 4, @chapter.versions.size
720
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
721
- assert_equal 0, chapter_v3.sections.size
722
- assert_equal 0, chapter_v3.paragraphs.size
723
- end
724
- end
725
-
726
- context "the version before a paragraph is destroyed" do
727
- should "have the one paragraph" do
728
- initial_paragraph_name = @section.paragraphs.first.name
729
- Timecop.travel 1.second.since
730
- @chapter.update_attributes(name: CHAPTER_NAMES[5])
731
- Timecop.travel 1.second.since
732
- @paragraph.destroy
733
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
734
- paragraphs = chapter_v3.sections.first.paragraphs
735
- assert_equal 1, paragraphs.size
736
- assert_equal initial_paragraph_name, paragraphs.first.name
737
- end
738
- end
739
-
740
- context "the version after a paragraph is destroyed" do
741
- should "have no paragraphs" do
742
- @paragraph.destroy
743
- Timecop.travel 1.second.since
744
- @chapter.update_attributes(name: CHAPTER_NAMES[5])
745
- chapter_v3 = @chapter.versions[3].reify(has_many: true)
746
- assert_equal 0, chapter_v3.paragraphs.size
747
- assert_equal [], chapter_v3.sections.first.paragraphs
748
- end
749
- end
750
- end
751
- end
752
-
753
- context "a chapter with one paragraph and one citation" do
754
- should "reify paragraphs and citations" do
755
- chapter = Chapter.create(name: CHAPTER_NAMES[0])
756
- section = Section.create(name: "Section One", chapter: chapter)
757
- paragraph = Paragraph.create(name: "Paragraph One", section: section)
758
- quotation = Quotation.create(chapter: chapter)
759
- citation = Citation.create(quotation: quotation)
760
- Timecop.travel 1.second.since
761
- chapter.update_attributes(name: CHAPTER_NAMES[1])
762
- assert_equal 2, chapter.versions.count
763
- paragraph.destroy
764
- citation.destroy
765
- reified = chapter.versions[1].reify(has_many: true)
766
- assert_equal [paragraph], reified.sections.first.paragraphs
767
- assert_equal [citation], reified.quotations.first.citations
768
- end
769
- end
770
- end
771
- end
772
-
773
- context "belongs_to associations" do
774
- context "Wotsit and Widget" do
775
- setup { @widget = Widget.create(name: "widget_0") }
776
-
777
- context "where the association is created between model versions" do
778
- setup do
779
- @wotsit = Wotsit.create(name: "wotsit_0")
780
- Timecop.travel 1.second.since
781
- @wotsit.update_attributes widget_id: @widget.id, name: "wotsit_1"
782
- end
783
-
784
- context "when reified" do
785
- setup { @wotsit0 = @wotsit.versions.last.reify(belongs_to: true) }
786
-
787
- should "see the associated as it was at the time" do
788
- assert_nil @wotsit0.widget
789
- end
790
-
791
- should "not persist changes to the live association" do
792
- assert_equal @widget, @wotsit.reload.widget
793
- end
794
- end
795
-
796
- context "and then the associated is updated between model versions" do
797
- setup do
798
- @widget.update_attributes name: "widget_1"
799
- @widget.update_attributes name: "widget_2"
800
- Timecop.travel 1.second.since
801
- @wotsit.update_attributes name: "wotsit_2"
802
- @widget.update_attributes name: "widget_3"
803
- end
804
-
805
- context "when reified" do
806
- setup { @wotsit1 = @wotsit.versions.last.reify(belongs_to: true) }
807
-
808
- should "see the associated as it was at the time" do
809
- assert_equal "widget_2", @wotsit1.widget.name
810
- end
811
-
812
- should "not persist changes to the live association" do
813
- assert_equal "widget_3", @wotsit.reload.widget.name
814
- end
815
- end
816
-
817
- context "when reified opting out of belongs_to reification" do
818
- setup { @wotsit1 = @wotsit.versions.last.reify(belongs_to: false) }
819
-
820
- should "see the associated as it is live" do
821
- assert_equal "widget_3", @wotsit1.widget.name
822
- end
823
- end
824
- end
825
-
826
- context "and then the associated is destroyed" do
827
- setup do
828
- @wotsit.update_attributes name: "wotsit_2"
829
- @widget.destroy
830
- end
831
-
832
- context "when reified with belongs_to: true" do
833
- setup { @wotsit2 = @wotsit.versions.last.reify(belongs_to: true) }
834
-
835
- should "see the associated as it was at the time" do
836
- assert_equal @widget, @wotsit2.widget
837
- end
838
-
839
- should "not persist changes to the live association" do
840
- assert_nil @wotsit.reload.widget
841
- end
842
-
843
- should "be able to persist the reified record" do
844
- assert_nothing_raised { @wotsit2.save! }
845
- end
846
- end
847
-
848
- context "when reified with belongs_to: false" do
849
- setup do
850
- @wotsit2 = @wotsit.versions.last.reify(belongs_to: false)
851
- end
852
-
853
- should "save should not re-create the widget record" do
854
- # Save succeeds because Wotsit does not validate presence of widget
855
- @wotsit2.save!
856
- assert_nil ::Widget.find_by(id: @widget.id)
857
- end
858
- end
859
-
860
- context "and then the model is updated" do
861
- setup do
862
- Timecop.travel 1.second.since
863
- @wotsit.update_attributes name: "wotsit_3"
864
- end
865
-
866
- context "when reified" do
867
- setup { @wotsit2 = @wotsit.versions.last.reify(belongs_to: true) }
868
-
869
- should "see the associated as it was the time" do
870
- assert_nil @wotsit2.widget
871
- end
872
- end
873
- end
874
- end
875
- end
876
-
877
- context "where the association is changed between model versions" do
878
- setup do
879
- @wotsit = @widget.create_wotsit(name: "wotsit_0")
880
- Timecop.travel 1.second.since
881
- @new_widget = Widget.create(name: "new_widget")
882
- @wotsit.update_attributes(widget_id: @new_widget.id, name: "wotsit_1")
883
- end
884
-
885
- context "when reified" do
886
- setup { @wotsit0 = @wotsit.versions.last.reify(belongs_to: true) }
887
-
888
- should "see the association as it was at the time" do
889
- assert_equal "widget_0", @wotsit0.widget.name
890
- end
891
-
892
- should "not persist changes to the live association" do
893
- assert_equal @new_widget, @wotsit.reload.widget
894
- end
895
- end
896
-
897
- context "when reified with option mark_for_destruction" do
898
- setup do
899
- @wotsit0 = @wotsit.versions.last.
900
- reify(belongs_to: true, mark_for_destruction: true)
901
- end
902
-
903
- should "should not mark the new associated for destruction" do
904
- assert_equal false, @new_widget.marked_for_destruction?
905
- end
906
- end
907
- end
908
- end
909
- end
910
-
911
- context "has_and_belongs_to_many associations" do
912
- context "foo and bar" do
913
- setup do
914
- @foo = FooHabtm.create(name: "foo")
915
- Timecop.travel 1.second.since
916
- end
917
-
918
- context "where the association is created between model versions" do
919
- setup do
920
- @foo.update_attributes(name: "foo1", bar_habtms: [BarHabtm.create(name: "bar")])
921
- end
922
-
923
- context "when reified" do
924
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
925
-
926
- should "see the associated as it was at the time" do
927
- assert_equal 0, @reified.bar_habtms.length
928
- end
929
-
930
- should "not persist changes to the live association" do
931
- assert_not_equal @reified.bar_habtms, @foo.reload.bar_habtms
932
- end
933
- end
934
- end
935
-
936
- context "where the association is changed between model versions" do
937
- setup do
938
- @foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
939
- Timecop.travel 1.second.since
940
- @foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar3")])
941
- end
942
-
943
- context "when reified" do
944
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
945
-
946
- should "see the association as it was at the time" do
947
- assert_equal "bar2", @reified.bar_habtms.first.name
948
- end
949
-
950
- should "not persist changes to the live association" do
951
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
952
- end
953
- end
954
-
955
- context "when reified with has_and_belongs_to_many: false" do
956
- setup { @reified = @foo.versions.last.reify }
957
-
958
- should "see the association as it is now" do
959
- assert_equal "bar3", @reified.bar_habtms.first.name
960
- end
961
- end
962
- end
963
-
964
- context "where the association is destroyed between model versions" do
965
- setup do
966
- @foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
967
- Timecop.travel 1.second.since
968
- @foo.update_attributes(name: "foo3", bar_habtms: [])
969
- end
970
-
971
- context "when reified" do
972
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
973
-
974
- should "see the association as it was at the time" do
975
- assert_equal "bar2", @reified.bar_habtms.first.name
976
- end
977
-
978
- should "not persist changes to the live association" do
979
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
980
- end
981
- end
982
- end
983
-
984
- context "where the unassociated model changes" do
985
- setup do
986
- @bar = BarHabtm.create(name: "bar2")
987
- @foo.update_attributes(name: "foo2", bar_habtms: [@bar])
988
- Timecop.travel 1.second.since
989
- @foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar4")])
990
- Timecop.travel 1.second.since
991
- @bar.update_attributes(name: "bar3")
992
- end
993
-
994
- context "when reified" do
995
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
996
-
997
- should "see the association as it was at the time" do
998
- assert_equal "bar2", @reified.bar_habtms.first.name
999
- end
1000
-
1001
- should "not persist changes to the live association" do
1002
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
1003
- end
1004
- end
1005
- end
1006
- end
1007
-
1008
- context "updated via nested attributes" do
1009
- setup do
1010
- @foo = FooHabtm.create(
1011
- name: "foo",
1012
- bar_habtms_attributes: [{ name: "bar" }]
1013
- )
1014
- Timecop.travel 1.second.since
1015
- @foo.update_attributes(
1016
- name: "foo2",
1017
- bar_habtms_attributes: [{ id: @foo.bar_habtms.first.id, name: "bar2" }]
1018
- )
1019
-
1020
- @reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
1021
- end
1022
-
1023
- should "see the associated object as it was at the time" do
1024
- assert_equal "bar", @reified.bar_habtms.first.name
1025
- end
1026
-
1027
- should "not persist changes to the live object" do
1028
- assert_not_equal @reified.bar_habtms.first.name, @foo.reload.bar_habtms.first.name
1029
- end
1030
- end
1031
- end
1032
- end