paper_trail 4.0.2 → 4.1.0

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