paper_trail 4.0.2 → 4.1.0

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.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +2 -0
  3. data/CHANGELOG.md +27 -0
  4. data/CONTRIBUTING.md +78 -5
  5. data/README.md +328 -268
  6. data/doc/bug_report_template.rb +65 -0
  7. data/gemfiles/3.0.gemfile +7 -4
  8. data/lib/generators/paper_trail/templates/add_object_changes_to_versions.rb +1 -1
  9. data/lib/generators/paper_trail/templates/create_versions.rb +14 -0
  10. data/lib/paper_trail.rb +11 -9
  11. data/lib/paper_trail/attributes_serialization.rb +89 -0
  12. data/lib/paper_trail/cleaner.rb +8 -1
  13. data/lib/paper_trail/config.rb +15 -18
  14. data/lib/paper_trail/frameworks/rails/controller.rb +16 -2
  15. data/lib/paper_trail/has_paper_trail.rb +102 -99
  16. data/lib/paper_trail/record_history.rb +59 -0
  17. data/lib/paper_trail/reifier.rb +270 -0
  18. data/lib/paper_trail/version_association_concern.rb +3 -1
  19. data/lib/paper_trail/version_concern.rb +60 -226
  20. data/lib/paper_trail/version_number.rb +2 -2
  21. data/paper_trail.gemspec +7 -10
  22. data/spec/models/animal_spec.rb +17 -0
  23. data/spec/models/callback_modifier_spec.rb +96 -0
  24. data/spec/models/json_version_spec.rb +20 -17
  25. data/spec/paper_trail/config_spec.rb +52 -0
  26. data/spec/spec_helper.rb +6 -0
  27. data/test/dummy/app/models/callback_modifier.rb +45 -0
  28. data/test/dummy/app/models/chapter.rb +9 -0
  29. data/test/dummy/app/models/citation.rb +5 -0
  30. data/test/dummy/app/models/paragraph.rb +5 -0
  31. data/test/dummy/app/models/quotation.rb +5 -0
  32. data/test/dummy/app/models/section.rb +6 -0
  33. data/test/dummy/config/database.postgres.yml +1 -1
  34. data/test/dummy/config/initializers/paper_trail.rb +3 -1
  35. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +33 -0
  36. data/test/dummy/db/schema.rb +27 -0
  37. data/test/test_helper.rb +36 -0
  38. data/test/unit/associations_test.rb +726 -0
  39. data/test/unit/inheritance_column_test.rb +6 -6
  40. data/test/unit/model_test.rb +62 -594
  41. data/test/unit/protected_attrs_test.rb +3 -2
  42. data/test/unit/version_test.rb +87 -69
  43. metadata +38 -2
@@ -1,7 +1,6 @@
1
1
  require 'test_helper'
2
2
 
3
3
  class InheritanceColumnTest < ActiveSupport::TestCase
4
-
5
4
  context 'STI models' do
6
5
  setup do
7
6
  @animal = Animal.create :name => 'Animal'
@@ -28,16 +27,17 @@ class InheritanceColumnTest < ActiveSupport::TestCase
28
27
 
29
28
  # For some reason `@dog.versions` doesn't include the final `destroy` version.
30
29
  # Neither do `@dog.versions.scoped` nor `@dog.versions(true)` nor `@dog.versions.reload`.
31
- dog_versions = PaperTrail::Version.where(:item_id => @dog.id)
30
+ dog_versions = PaperTrail::Version.where(:item_id => @dog.id).
31
+ order(PaperTrail.timestamp_field)
32
32
  assert_equal 4, dog_versions.count
33
33
  assert_nil dog_versions.first.reify
34
- dog_versions[1..-1].each { |v| assert_equal 'Dog', v.reify.class.name }
34
+ assert_equal %w[NilClass Dog Dog Dog], dog_versions.map { |v| v.reify.class.name }
35
35
 
36
- cat_versions = PaperTrail::Version.where(:item_id => @cat.id)
36
+ cat_versions = PaperTrail::Version.where(:item_id => @cat.id).
37
+ order(PaperTrail.timestamp_field)
37
38
  assert_equal 4, cat_versions.count
38
39
  assert_nil cat_versions.first.reify
39
- cat_versions[1..-1].each { |v| assert_equal 'Cat', v.reify.class.name }
40
+ assert_equal %w[NilClass Cat Cat Cat], cat_versions.map { |v| v.reify.class.name }
40
41
  end
41
42
  end
42
-
43
43
  end
@@ -228,8 +228,8 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
228
228
  'id' => [nil, @widget.id]
229
229
  }
230
230
 
231
- assert_equal Time, @widget.versions.last.changeset['updated_at'][1].class
232
- assert_equal changes, @widget.versions.last.changeset
231
+ assert_kind_of Time, @widget.versions.last.changeset['updated_at'][1]
232
+ assert_changes_equal changes, @widget.versions.last.changeset
233
233
  end
234
234
 
235
235
  context 'and then updated without any changes' do
@@ -375,7 +375,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
375
375
 
376
376
  should 'be available in its previous version' do
377
377
  assert_equal @widget.id, @reified_widget.id
378
- assert_equal @widget.attributes, @reified_widget.attributes
378
+ assert_attributes_equal @widget.attributes, @reified_widget.attributes
379
379
  end
380
380
 
381
381
  should 'be re-creatable from its previous version' do
@@ -978,100 +978,94 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
978
978
  end
979
979
  end
980
980
 
981
- # `serialized_attributes` is deprecated in ActiveRecord 5.0
982
- if ::ActiveRecord::VERSION::MAJOR < 5
983
- context 'When an attribute has a custom serializer' do
981
+ context 'When an attribute has a custom serializer' do
982
+ setup do
983
+ @person = Person.new(:time_zone => "Samoa")
984
+ end
985
+
986
+ should "be an instance of ActiveSupport::TimeZone" do
987
+ assert_equal ActiveSupport::TimeZone, @person.time_zone.class
988
+ end
989
+
990
+ context 'when the model is saved' do
984
991
  setup do
985
- PaperTrail.config.serialized_attributes = true
986
- @person = Person.new(:time_zone => "Samoa")
992
+ @changes_before_save = @person.changes.dup
993
+ @person.save!
987
994
  end
988
995
 
989
- teardown { PaperTrail.config.serialized_attributes = false }
996
+ # Test for serialization:
997
+ should 'version.object_changes should not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
998
+ assert @person.versions.last.object_changes.length < 105, "object_changes length was #{@person.versions.last.object_changes.length}"
999
+ end
1000
+ # It should store the serialized value.
1001
+ should 'version.object_changes attribute should have stored the value returned by the attribute serializer' do
1002
+ as_stored_in_version = HashWithIndifferentAccess[YAML::load(@person.versions.last.object_changes)]
1003
+ assert_equal [nil, 'Samoa'], as_stored_in_version[:time_zone]
1004
+ serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
1005
+ assert_equal serialized_value, as_stored_in_version[:time_zone].last
1006
+ end
990
1007
 
991
- should "be an instance of ActiveSupport::TimeZone" do
992
- assert_equal ActiveSupport::TimeZone, @person.time_zone.class
1008
+ # Tests for unserialization:
1009
+ should 'version.changeset should convert the attribute value back to its original, unserialized value' do
1010
+ unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
1011
+ assert_equal unserialized_value, @person.versions.last.changeset[:time_zone].last
1012
+ end
1013
+ should "record.changes (before save) returns the original, unserialized values" do
1014
+ assert_equal [NilClass, ActiveSupport::TimeZone], @changes_before_save[:time_zone].map(&:class)
1015
+ end
1016
+ should 'version.changeset should be the same as record.changes was before the save' do
1017
+ assert_equal @changes_before_save, @person.versions.last.changeset.delete_if { |key, val| key.to_sym == :id }
1018
+ assert_equal [NilClass, ActiveSupport::TimeZone], @person.versions.last.changeset[:time_zone].map(&:class)
993
1019
  end
994
1020
 
995
- context 'when the model is saved' do
1021
+ context 'when that attribute is updated' do
996
1022
  setup do
1023
+ @attribute_value_before_change = @person.time_zone
1024
+ @person.assign_attributes({ :time_zone => 'Pacific Time (US & Canada)' })
997
1025
  @changes_before_save = @person.changes.dup
998
1026
  @person.save!
999
1027
  end
1000
1028
 
1001
- # Test for serialization:
1029
+ # Tests for serialization:
1030
+ # Before the serialized attributes fix, the object/object_changes value that was stored was ridiculously long (58723).
1031
+ should 'version.object should not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
1032
+ assert @person.versions.last.object.length < 105, "object length was #{@person.versions.last.object.length}"
1033
+ end
1034
+ # Need an additional clause to detect what version of ActiveRecord is being used for this test because AR4 injects the `updated_at` column into the changeset for updates to models
1002
1035
  should 'version.object_changes should not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
1003
- assert @person.versions.last.object_changes.length < 105, "object_changes length was #{@person.versions.last.object_changes.length}"
1036
+ assert @person.versions.last.object_changes.length < (ActiveRecord::VERSION::MAJOR < 4 ? 105 : 118), "object_changes length was #{@person.versions.last.object_changes.length}"
1037
+ end
1038
+ # But now it stores the short, serialized value.
1039
+ should 'version.object attribute should have stored the value returned by the attribute serializer' do
1040
+ as_stored_in_version = HashWithIndifferentAccess[YAML::load(@person.versions.last.object)]
1041
+ assert_equal 'Samoa', as_stored_in_version[:time_zone]
1042
+ serialized_value = Person::TimeZoneSerializer.dump(@attribute_value_before_change)
1043
+ assert_equal serialized_value, as_stored_in_version[:time_zone]
1004
1044
  end
1005
- # It should store the serialized value.
1006
1045
  should 'version.object_changes attribute should have stored the value returned by the attribute serializer' do
1007
1046
  as_stored_in_version = HashWithIndifferentAccess[YAML::load(@person.versions.last.object_changes)]
1008
- assert_equal [nil, 'Samoa'], as_stored_in_version[:time_zone]
1047
+ assert_equal ['Samoa', 'Pacific Time (US & Canada)'], as_stored_in_version[:time_zone]
1009
1048
  serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
1010
1049
  assert_equal serialized_value, as_stored_in_version[:time_zone].last
1011
1050
  end
1012
1051
 
1013
1052
  # Tests for unserialization:
1053
+ should 'version.reify should convert the attribute value back to its original, unserialized value' do
1054
+ unserialized_value = Person::TimeZoneSerializer.load(@attribute_value_before_change)
1055
+ assert_equal unserialized_value, @person.versions.last.reify.time_zone
1056
+ end
1014
1057
  should 'version.changeset should convert the attribute value back to its original, unserialized value' do
1015
1058
  unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
1016
1059
  assert_equal unserialized_value, @person.versions.last.changeset[:time_zone].last
1017
1060
  end
1018
1061
  should "record.changes (before save) returns the original, unserialized values" do
1019
- assert_equal [NilClass, ActiveSupport::TimeZone], @changes_before_save[:time_zone].map(&:class)
1062
+ assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @changes_before_save[:time_zone].map(&:class)
1020
1063
  end
1021
1064
  should 'version.changeset should be the same as record.changes was before the save' do
1022
- assert_equal @changes_before_save, @person.versions.last.changeset.delete_if { |key, val| key.to_sym == :id }
1023
- assert_equal [NilClass, ActiveSupport::TimeZone], @person.versions.last.changeset[:time_zone].map(&:class)
1065
+ assert_equal @changes_before_save, @person.versions.last.changeset
1066
+ assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @person.versions.last.changeset[:time_zone].map(&:class)
1024
1067
  end
1025
1068
 
1026
- context 'when that attribute is updated' do
1027
- setup do
1028
- @attribute_value_before_change = @person.time_zone
1029
- @person.assign_attributes({ :time_zone => 'Pacific Time (US & Canada)' })
1030
- @changes_before_save = @person.changes.dup
1031
- @person.save!
1032
- end
1033
-
1034
- # Tests for serialization:
1035
- # Before the serialized attributes fix, the object/object_changes value that was stored was ridiculously long (58723).
1036
- should 'version.object should not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
1037
- assert @person.versions.last.object.length < 105, "object length was #{@person.versions.last.object.length}"
1038
- end
1039
- # Need an additional clause to detect what version of ActiveRecord is being used for this test because AR4 injects the `updated_at` column into the changeset for updates to models
1040
- should 'version.object_changes should not have stored the default, ridiculously long (to_yaml) serialization of the TimeZone object' do
1041
- assert @person.versions.last.object_changes.length < (ActiveRecord::VERSION::MAJOR < 4 ? 105 : 118), "object_changes length was #{@person.versions.last.object_changes.length}"
1042
- end
1043
- # But now it stores the short, serialized value.
1044
- should 'version.object attribute should have stored the value returned by the attribute serializer' do
1045
- as_stored_in_version = HashWithIndifferentAccess[YAML::load(@person.versions.last.object)]
1046
- assert_equal 'Samoa', as_stored_in_version[:time_zone]
1047
- serialized_value = Person::TimeZoneSerializer.dump(@attribute_value_before_change)
1048
- assert_equal serialized_value, as_stored_in_version[:time_zone]
1049
- end
1050
- should 'version.object_changes attribute should have stored the value returned by the attribute serializer' do
1051
- as_stored_in_version = HashWithIndifferentAccess[YAML::load(@person.versions.last.object_changes)]
1052
- assert_equal ['Samoa', 'Pacific Time (US & Canada)'], as_stored_in_version[:time_zone]
1053
- serialized_value = Person::TimeZoneSerializer.dump(@person.time_zone)
1054
- assert_equal serialized_value, as_stored_in_version[:time_zone].last
1055
- end
1056
-
1057
- # Tests for unserialization:
1058
- should 'version.reify should convert the attribute value back to its original, unserialized value' do
1059
- unserialized_value = Person::TimeZoneSerializer.load(@attribute_value_before_change)
1060
- assert_equal unserialized_value, @person.versions.last.reify.time_zone
1061
- end
1062
- should 'version.changeset should convert the attribute value back to its original, unserialized value' do
1063
- unserialized_value = Person::TimeZoneSerializer.load(@person.time_zone)
1064
- assert_equal unserialized_value, @person.versions.last.changeset[:time_zone].last
1065
- end
1066
- should "record.changes (before save) returns the original, unserialized values" do
1067
- assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @changes_before_save[:time_zone].map(&:class)
1068
- end
1069
- should 'version.changeset should be the same as record.changes was before the save' do
1070
- assert_equal @changes_before_save, @person.versions.last.changeset
1071
- assert_equal [ActiveSupport::TimeZone, ActiveSupport::TimeZone], @person.versions.last.changeset[:time_zone].map(&:class)
1072
- end
1073
-
1074
- end
1075
1069
  end
1076
1070
  end
1077
1071
  end
@@ -1377,529 +1371,3 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1377
1371
  end
1378
1372
  end
1379
1373
  end
1380
-
1381
-
1382
- class HasPaperTrailModelTransactionalTest < ActiveSupport::TestCase
1383
- # These would have been done in test_helper.rb if using_mysql? is true
1384
- unless using_mysql?
1385
- self.use_transactional_fixtures = false
1386
- setup { DatabaseCleaner.start }
1387
- end
1388
-
1389
- teardown do
1390
- Timecop.return
1391
- # This would have been done in test_helper.rb if using_mysql? is true
1392
- DatabaseCleaner.clean unless using_mysql?
1393
- end
1394
-
1395
- context 'A model with a has_one association' do
1396
- setup { @widget = Widget.create :name => 'widget_0' }
1397
-
1398
- context 'before the associated was created' do
1399
- setup do
1400
- @widget.update_attributes :name => 'widget_1'
1401
- @wotsit = @widget.create_wotsit :name => 'wotsit_0'
1402
- end
1403
-
1404
- context 'when reified' do
1405
- setup { @widget_0 = @widget.versions.last.reify(:has_one => true) }
1406
-
1407
- should 'see the associated as it was at the time' do
1408
- assert_nil @widget_0.wotsit
1409
- end
1410
-
1411
- should 'not persist changes to the live association' do
1412
- assert_equal @wotsit, @widget.wotsit(true)
1413
- end
1414
- end
1415
- end
1416
-
1417
- context 'where the association is created between model versions' do
1418
- setup do
1419
- @wotsit = @widget.create_wotsit :name => 'wotsit_0'
1420
- Timecop.travel 1.second.since
1421
- @widget.update_attributes :name => 'widget_1'
1422
- end
1423
-
1424
- context 'when reified' do
1425
- setup { @widget_0 = @widget.versions.last.reify(:has_one => true) }
1426
-
1427
- should 'see the associated as it was at the time' do
1428
- assert_equal 'wotsit_0', @widget_0.wotsit.name
1429
- end
1430
-
1431
- should 'not persist changes to the live association' do
1432
- assert_equal @wotsit, @widget.wotsit(true)
1433
- end
1434
- end
1435
-
1436
- context 'and then the associated is updated between model versions' do
1437
- setup do
1438
- @wotsit.update_attributes :name => 'wotsit_1'
1439
- @wotsit.update_attributes :name => 'wotsit_2'
1440
- Timecop.travel 1.second.since
1441
- @widget.update_attributes :name => 'widget_2'
1442
- @wotsit.update_attributes :name => 'wotsit_3'
1443
- end
1444
-
1445
- context 'when reified' do
1446
- setup { @widget_1 = @widget.versions.last.reify(:has_one => true) }
1447
-
1448
- should 'see the associated as it was at the time' do
1449
- assert_equal 'wotsit_2', @widget_1.wotsit.name
1450
- end
1451
-
1452
- should 'not persist changes to the live association' do
1453
- assert_equal 'wotsit_3', @widget.wotsit(true).name
1454
- end
1455
- end
1456
-
1457
- context 'when reified opting out of has_one reification' do
1458
- setup { @widget_1 = @widget.versions.last.reify(:has_one => false) }
1459
-
1460
- should 'see the associated as it is live' do
1461
- assert_equal 'wotsit_3', @widget_1.wotsit.name
1462
- end
1463
- end
1464
- end
1465
-
1466
- context 'and then the associated is destroyed' do
1467
- setup do
1468
- @wotsit.destroy
1469
- end
1470
-
1471
- context 'when reify' do
1472
- setup { @widget_1 = @widget.versions.last.reify(:has_one => true) }
1473
-
1474
- should 'see the associated as it was at the time' do
1475
- assert_equal @wotsit, @widget_1.wotsit
1476
- end
1477
-
1478
- should 'not persist changes to the live association' do
1479
- assert_nil @widget.wotsit(true)
1480
- end
1481
- end
1482
-
1483
- context 'and then the model is updated' do
1484
- setup do
1485
- Timecop.travel 1.second.since
1486
- @widget.update_attributes :name => 'widget_3'
1487
- end
1488
-
1489
- context 'when reified' do
1490
- setup { @widget_2 = @widget.versions.last.reify(:has_one => true) }
1491
-
1492
- should 'see the associated as it was at the time' do
1493
- assert_nil @widget_2.wotsit
1494
- end
1495
- end
1496
- end
1497
- end
1498
- end
1499
- end
1500
-
1501
- context 'A model with a has_many association' do
1502
- setup { @customer = Customer.create :name => 'customer_0' }
1503
-
1504
- context 'updated before the associated was created' do
1505
- setup do
1506
- @customer.update_attributes! :name => 'customer_1'
1507
- @customer.orders.create! :order_date => Date.today
1508
- end
1509
-
1510
- context 'when reified' do
1511
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
1512
-
1513
- should 'see the associated as it was at the time' do
1514
- assert_equal [], @customer_0.orders
1515
- end
1516
-
1517
- should 'not persist changes to the live association' do
1518
- assert_not_equal [], @customer.orders(true)
1519
- end
1520
- end
1521
-
1522
- context 'when reified with option mark_for_destruction' do
1523
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1524
-
1525
- should 'mark the associated for destruction' do
1526
- assert_equal [true], @customer_0.orders.map(&:marked_for_destruction?)
1527
- end
1528
- end
1529
- end
1530
-
1531
- context 'where the association is created between model versions' do
1532
- setup do
1533
- @order = @customer.orders.create! :order_date => 'order_date_0'
1534
- Timecop.travel 1.second.since
1535
- @customer.update_attributes :name => 'customer_1'
1536
- end
1537
-
1538
- context 'when reified' do
1539
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
1540
-
1541
- should 'see the associated as it was at the time' do
1542
- assert_equal ['order_date_0'], @customer_0.orders.map(&:order_date)
1543
- end
1544
- end
1545
-
1546
- context 'and then a nested has_many association is created' do
1547
- setup do
1548
- @order.line_items.create! :product => 'product_0'
1549
- end
1550
-
1551
- context 'when reified' do
1552
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
1553
-
1554
- should 'see the live version of the nested association' do
1555
- assert_equal ['product_0'], @customer_0.orders.first.line_items.map(&:product)
1556
- end
1557
- end
1558
- end
1559
-
1560
- context 'and then the associated is updated between model versions' do
1561
- setup do
1562
- @order.update_attributes :order_date => 'order_date_1'
1563
- @order.update_attributes :order_date => 'order_date_2'
1564
- Timecop.travel 1.second.since
1565
- @customer.update_attributes :name => 'customer_2'
1566
- @order.update_attributes :order_date => 'order_date_3'
1567
- end
1568
-
1569
- context 'when reified' do
1570
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
1571
-
1572
- should 'see the associated as it was at the time' do
1573
- assert_equal ['order_date_2'], @customer_1.orders.map(&:order_date)
1574
- end
1575
-
1576
- should 'not persist changes to the live association' do
1577
- assert_equal ['order_date_3'], @customer.orders(true).map(&:order_date)
1578
- end
1579
- end
1580
-
1581
- context 'when reified opting out of has_many reification' do
1582
- setup { @customer_1 = @customer.versions.last.reify(:has_many => false) }
1583
-
1584
- should 'see the associated as it is live' do
1585
- assert_equal ['order_date_3'], @customer_1.orders.map(&:order_date)
1586
- end
1587
- end
1588
-
1589
- context 'and then the associated is destroyed' do
1590
- setup do
1591
- @order.destroy
1592
- end
1593
-
1594
- context 'when reified' do
1595
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
1596
-
1597
- should 'see the associated as it was at the time' do
1598
- assert_equal ['order_date_2'], @customer_1.orders.map(&:order_date)
1599
- end
1600
-
1601
- should 'not persist changes to the live association' do
1602
- assert_equal [], @customer.orders(true)
1603
- end
1604
- end
1605
- end
1606
- end
1607
-
1608
- context 'and then the associated is destroyed' do
1609
- setup do
1610
- @order.destroy
1611
- end
1612
-
1613
- context 'when reified' do
1614
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
1615
-
1616
- should 'see the associated as it was at the time' do
1617
- assert_equal [@order.order_date], @customer_1.orders.map(&:order_date)
1618
- end
1619
-
1620
- should 'not persist changes to the live association' do
1621
- assert_equal [], @customer.orders(true)
1622
- end
1623
- end
1624
- end
1625
-
1626
- context 'and then the associated is destroyed between model versions' do
1627
- setup do
1628
- @order.destroy
1629
- Timecop.travel 1.second.since
1630
- @customer.update_attributes :name => 'customer_2'
1631
- end
1632
-
1633
- context 'when reified' do
1634
- setup { @customer_1 = @customer.versions.last.reify(:has_many => true) }
1635
-
1636
- should 'see the associated as it was at the time' do
1637
- assert_equal [], @customer_1.orders
1638
- end
1639
- end
1640
- end
1641
-
1642
- context 'and then another association is added' do
1643
- setup do
1644
- @customer.orders.create! :order_date => 'order_date_1'
1645
- end
1646
-
1647
- context 'when reified' do
1648
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true) }
1649
-
1650
- should 'see the associated as it was at the time' do
1651
- assert_equal ['order_date_0'], @customer_0.orders.map(&:order_date)
1652
- end
1653
-
1654
- should 'not persist changes to the live association' do
1655
- assert_equal ['order_date_0', 'order_date_1'], @customer.orders(true).map(&:order_date).sort
1656
- end
1657
- end
1658
-
1659
- context 'when reified with option mark_for_destruction' do
1660
- setup { @customer_0 = @customer.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1661
-
1662
- should 'mark the newly associated for destruction' do
1663
- assert @customer_0.orders.detect { |o| o.order_date == 'order_date_1'}.marked_for_destruction?
1664
- end
1665
- end
1666
- end
1667
- end
1668
- end
1669
-
1670
- context 'A model with a has_many through association' do
1671
- setup { @book = Book.create :title => 'book_0' }
1672
-
1673
- context 'updated before the associated was created' do
1674
- setup do
1675
- @book.update_attributes! :title => 'book_1'
1676
- @book.authors.create! :name => 'author_0'
1677
- end
1678
-
1679
- context 'when reified' do
1680
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1681
-
1682
- should 'see the associated as it was at the time' do
1683
- assert_equal [], @book_0.authors
1684
- end
1685
-
1686
- should 'not persist changes to the live association' do
1687
- assert_equal ['author_0'], @book.authors(true).map(&:name)
1688
- end
1689
- end
1690
-
1691
- context 'when reified with option mark_for_destruction' do
1692
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1693
-
1694
- should 'mark the associated for destruction' do
1695
- assert_equal [true], @book_0.authors.map(&:marked_for_destruction?)
1696
- end
1697
-
1698
- should 'mark the associated-through for destruction' do
1699
- assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
1700
- end
1701
- end
1702
- end
1703
-
1704
- context 'updated before it is associated with an existing one' do
1705
- setup do
1706
- person_existing = Person.create(:name => 'person_existing')
1707
- Timecop.travel 1.second.since
1708
- @book.update_attributes! :title => 'book_1'
1709
- @book.authors << person_existing
1710
- end
1711
-
1712
- context 'when reified' do
1713
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1714
-
1715
- should 'see the associated as it was at the time' do
1716
- assert_equal [], @book_0.authors
1717
- end
1718
- end
1719
-
1720
- context 'when reified with option mark_for_destruction' do
1721
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1722
-
1723
- should 'not mark the associated for destruction' do
1724
- assert_equal [false], @book_0.authors.map(&:marked_for_destruction?)
1725
- end
1726
-
1727
- should 'mark the associated-through for destruction' do
1728
- assert_equal [true], @book_0.authorships.map(&:marked_for_destruction?)
1729
- end
1730
- end
1731
- end
1732
-
1733
- context 'where the association is created between model versions' do
1734
- setup do
1735
- @author = @book.authors.create! :name => 'author_0'
1736
- @person_existing = Person.create(:name => 'person_existing')
1737
- Timecop.travel 1.second.since
1738
- @book.update_attributes! :title => 'book_1'
1739
- end
1740
-
1741
- context 'when reified' do
1742
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1743
-
1744
- should 'see the associated as it was at the time' do
1745
- assert_equal ['author_0'], @book_0.authors.map(&:name)
1746
- end
1747
- end
1748
-
1749
- context 'and then the associated is updated between model versions' do
1750
- setup do
1751
- @author.update_attributes :name => 'author_1'
1752
- @author.update_attributes :name => 'author_2'
1753
- Timecop.travel 1.second.since
1754
- @book.update_attributes :title => 'book_2'
1755
- @author.update_attributes :name => 'author_3'
1756
- end
1757
-
1758
- context 'when reified' do
1759
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
1760
-
1761
- should 'see the associated as it was at the time' do
1762
- assert_equal ['author_2'], @book_1.authors.map(&:name)
1763
- end
1764
-
1765
- should 'not persist changes to the live association' do
1766
- assert_equal ['author_3'], @book.authors(true).map(&:name)
1767
- end
1768
- end
1769
-
1770
- context 'when reified opting out of has_many reification' do
1771
- setup { @book_1 = @book.versions.last.reify(:has_many => false) }
1772
-
1773
- should 'see the associated as it is live' do
1774
- assert_equal ['author_3'], @book_1.authors.map(&:name)
1775
- end
1776
- end
1777
- end
1778
-
1779
- context 'and then the associated is destroyed' do
1780
- setup do
1781
- @author.destroy
1782
- end
1783
-
1784
- context 'when reified' do
1785
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
1786
-
1787
- should 'see the associated as it was at the time' do
1788
- assert_equal [@author.name], @book_1.authors.map(&:name)
1789
- end
1790
-
1791
- should 'not persist changes to the live association' do
1792
- assert_equal [], @book.authors(true)
1793
- end
1794
- end
1795
- end
1796
-
1797
- context 'and then the associated is destroyed between model versions' do
1798
- setup do
1799
- @author.destroy
1800
- Timecop.travel 1.second.since
1801
- @book.update_attributes :title => 'book_2'
1802
- end
1803
-
1804
- context 'when reified' do
1805
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
1806
-
1807
- should 'see the associated as it was at the time' do
1808
- assert_equal [], @book_1.authors
1809
- end
1810
- end
1811
- end
1812
-
1813
- context 'and then the associated is dissociated between model versions' do
1814
- setup do
1815
- @book.authors = []
1816
- Timecop.travel 1.second.since
1817
- @book.update_attributes :title => 'book_2'
1818
- end
1819
-
1820
- context 'when reified' do
1821
- setup { @book_1 = @book.versions.last.reify(:has_many => true) }
1822
-
1823
- should 'see the associated as it was at the time' do
1824
- assert_equal [], @book_1.authors
1825
- end
1826
- end
1827
- end
1828
-
1829
- context 'and then another associated is created' do
1830
- setup do
1831
- @book.authors.create! :name => 'author_1'
1832
- end
1833
-
1834
- context 'when reified' do
1835
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1836
-
1837
- should 'only see the first associated' do
1838
- assert_equal ['author_0'], @book_0.authors.map(&:name)
1839
- end
1840
-
1841
- should 'not persist changes to the live association' do
1842
- assert_equal ['author_0', 'author_1'], @book.authors(true).map(&:name)
1843
- end
1844
- end
1845
-
1846
- context 'when reified with option mark_for_destruction' do
1847
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1848
-
1849
- should 'mark the newly associated for destruction' do
1850
- assert @book_0.authors.detect { |a| a.name == 'author_1' }.marked_for_destruction?
1851
- end
1852
-
1853
- should 'mark the newly associated-through for destruction' do
1854
- assert @book_0.authorships.detect { |as| as.person.name == 'author_1' }.marked_for_destruction?
1855
- end
1856
- end
1857
- end
1858
-
1859
- context 'and then an existing one is associated' do
1860
- setup do
1861
- @book.authors << @person_existing
1862
- end
1863
-
1864
- context 'when reified' do
1865
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1866
-
1867
- should 'only see the first associated' do
1868
- assert_equal ['author_0'], @book_0.authors.map(&:name)
1869
- end
1870
-
1871
- should 'not persist changes to the live association' do
1872
- assert_equal ['author_0', 'person_existing'], @book.authors(true).map(&:name).sort
1873
- end
1874
- end
1875
-
1876
- context 'when reified with option mark_for_destruction' do
1877
- setup { @book_0 = @book.versions.last.reify(:has_many => true, :mark_for_destruction => true) }
1878
-
1879
- should 'not mark the newly associated for destruction' do
1880
- assert !@book_0.authors.detect { |a| a.name == 'person_existing' }.marked_for_destruction?
1881
- end
1882
-
1883
- should 'mark the newly associated-through for destruction' do
1884
- assert @book_0.authorships.detect { |as| as.person.name == 'person_existing' }.marked_for_destruction?
1885
- end
1886
- end
1887
- end
1888
- end
1889
-
1890
- context 'updated before the associated without paper_trail was created' do
1891
- setup do
1892
- @book.update_attributes! :title => 'book_1'
1893
- @book.editors.create! :name => 'editor_0'
1894
- end
1895
-
1896
- context 'when reified' do
1897
- setup { @book_0 = @book.versions.last.reify(:has_many => true) }
1898
-
1899
- should 'see the live association' do
1900
- assert_equal ['editor_0'], @book_0.editors.map(&:name)
1901
- end
1902
- end
1903
- end
1904
- end
1905
- end