paper_trail 5.2.3 → 11.0.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 (198) hide show
  1. checksums.yaml +5 -5
  2. data/lib/generators/paper_trail/install/USAGE +3 -0
  3. data/lib/generators/paper_trail/install/install_generator.rb +75 -0
  4. data/lib/generators/paper_trail/{templates/add_object_changes_to_versions.rb → install/templates/add_object_changes_to_versions.rb.erb} +1 -1
  5. data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +36 -0
  6. data/lib/generators/paper_trail/migration_generator.rb +38 -0
  7. data/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
  8. data/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +85 -0
  9. data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +17 -0
  10. data/lib/paper_trail.rb +82 -130
  11. data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +27 -0
  12. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +15 -44
  13. data/lib/paper_trail/attribute_serializers/object_attribute.rb +2 -0
  14. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +2 -0
  15. data/lib/paper_trail/cleaner.rb +3 -1
  16. data/lib/paper_trail/compatibility.rb +51 -0
  17. data/lib/paper_trail/config.rb +11 -49
  18. data/lib/paper_trail/events/base.rb +323 -0
  19. data/lib/paper_trail/events/create.rb +32 -0
  20. data/lib/paper_trail/events/destroy.rb +42 -0
  21. data/lib/paper_trail/events/update.rb +60 -0
  22. data/lib/paper_trail/frameworks/active_record.rb +2 -1
  23. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +8 -3
  24. data/lib/paper_trail/frameworks/cucumber.rb +5 -3
  25. data/lib/paper_trail/frameworks/rails.rb +2 -0
  26. data/lib/paper_trail/frameworks/rails/controller.rb +33 -43
  27. data/lib/paper_trail/frameworks/rails/engine.rb +34 -1
  28. data/lib/paper_trail/frameworks/rspec.rb +17 -4
  29. data/lib/paper_trail/frameworks/rspec/helpers.rb +2 -0
  30. data/lib/paper_trail/has_paper_trail.rb +22 -310
  31. data/lib/paper_trail/model_config.rb +157 -109
  32. data/lib/paper_trail/queries/versions/where_object.rb +65 -0
  33. data/lib/paper_trail/queries/versions/where_object_changes.rb +75 -0
  34. data/lib/paper_trail/record_history.rb +3 -9
  35. data/lib/paper_trail/record_trail.rb +169 -319
  36. data/lib/paper_trail/reifier.rb +53 -374
  37. data/lib/paper_trail/request.rb +166 -0
  38. data/lib/paper_trail/serializers/json.rb +9 -10
  39. data/lib/paper_trail/serializers/yaml.rb +15 -28
  40. data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +48 -0
  41. data/lib/paper_trail/version_concern.rb +160 -155
  42. data/lib/paper_trail/version_number.rb +12 -4
  43. metadata +77 -372
  44. data/.github/CONTRIBUTING.md +0 -109
  45. data/.github/ISSUE_TEMPLATE.md +0 -13
  46. data/.gitignore +0 -23
  47. data/.rspec +0 -2
  48. data/.rubocop.yml +0 -99
  49. data/.rubocop_todo.yml +0 -22
  50. data/.travis.yml +0 -41
  51. data/Appraisals +0 -38
  52. data/CHANGELOG.md +0 -560
  53. data/Gemfile +0 -2
  54. data/MIT-LICENSE +0 -20
  55. data/README.md +0 -1654
  56. data/Rakefile +0 -30
  57. data/doc/bug_report_template.rb +0 -69
  58. data/doc/warning_about_not_setting_whodunnit.md +0 -32
  59. data/gemfiles/ar3.gemfile +0 -19
  60. data/gemfiles/ar4.gemfile +0 -8
  61. data/gemfiles/ar5.gemfile +0 -9
  62. data/lib/generators/paper_trail/USAGE +0 -2
  63. data/lib/generators/paper_trail/default_initializer.rb +0 -0
  64. data/lib/generators/paper_trail/install_generator.rb +0 -57
  65. data/lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb +0 -13
  66. data/lib/generators/paper_trail/templates/create_version_associations.rb +0 -22
  67. data/lib/generators/paper_trail/templates/create_versions.rb +0 -80
  68. data/lib/paper_trail/attribute_serializers/legacy_active_record_shim.rb +0 -48
  69. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +0 -11
  70. data/lib/paper_trail/frameworks/sinatra.rb +0 -40
  71. data/lib/paper_trail/version_association_concern.rb +0 -17
  72. data/paper_trail.gemspec +0 -56
  73. data/spec/generators/install_generator_spec.rb +0 -66
  74. data/spec/generators/paper_trail/templates/create_versions_spec.rb +0 -51
  75. data/spec/models/animal_spec.rb +0 -36
  76. data/spec/models/boolit_spec.rb +0 -48
  77. data/spec/models/callback_modifier_spec.rb +0 -96
  78. data/spec/models/car_spec.rb +0 -13
  79. data/spec/models/custom_primary_key_record_spec.rb +0 -18
  80. data/spec/models/fluxor_spec.rb +0 -17
  81. data/spec/models/gadget_spec.rb +0 -68
  82. data/spec/models/joined_version_spec.rb +0 -47
  83. data/spec/models/json_version_spec.rb +0 -102
  84. data/spec/models/kitchen/banana_spec.rb +0 -14
  85. data/spec/models/not_on_update_spec.rb +0 -22
  86. data/spec/models/post_with_status_spec.rb +0 -50
  87. data/spec/models/skipper_spec.rb +0 -46
  88. data/spec/models/thing_spec.rb +0 -11
  89. data/spec/models/truck_spec.rb +0 -5
  90. data/spec/models/vehicle_spec.rb +0 -5
  91. data/spec/models/version_spec.rb +0 -272
  92. data/spec/models/widget_spec.rb +0 -343
  93. data/spec/modules/paper_trail_spec.rb +0 -27
  94. data/spec/modules/version_concern_spec.rb +0 -31
  95. data/spec/modules/version_number_spec.rb +0 -43
  96. data/spec/paper_trail/config_spec.rb +0 -33
  97. data/spec/paper_trail_spec.rb +0 -79
  98. data/spec/rails_helper.rb +0 -34
  99. data/spec/requests/articles_spec.rb +0 -34
  100. data/spec/spec_helper.rb +0 -114
  101. data/spec/support/alt_db_init.rb +0 -54
  102. data/test/custom_json_serializer.rb +0 -13
  103. data/test/dummy/Rakefile +0 -7
  104. data/test/dummy/app/controllers/application_controller.rb +0 -33
  105. data/test/dummy/app/controllers/articles_controller.rb +0 -20
  106. data/test/dummy/app/controllers/test_controller.rb +0 -5
  107. data/test/dummy/app/controllers/widgets_controller.rb +0 -32
  108. data/test/dummy/app/helpers/application_helper.rb +0 -2
  109. data/test/dummy/app/models/animal.rb +0 -6
  110. data/test/dummy/app/models/article.rb +0 -24
  111. data/test/dummy/app/models/authorship.rb +0 -5
  112. data/test/dummy/app/models/bar_habtm.rb +0 -4
  113. data/test/dummy/app/models/book.rb +0 -9
  114. data/test/dummy/app/models/boolit.rb +0 -4
  115. data/test/dummy/app/models/callback_modifier.rb +0 -45
  116. data/test/dummy/app/models/car.rb +0 -3
  117. data/test/dummy/app/models/cat.rb +0 -2
  118. data/test/dummy/app/models/chapter.rb +0 -9
  119. data/test/dummy/app/models/citation.rb +0 -5
  120. data/test/dummy/app/models/custom_primary_key_record.rb +0 -13
  121. data/test/dummy/app/models/customer.rb +0 -4
  122. data/test/dummy/app/models/document.rb +0 -4
  123. data/test/dummy/app/models/dog.rb +0 -2
  124. data/test/dummy/app/models/editor.rb +0 -4
  125. data/test/dummy/app/models/editorship.rb +0 -5
  126. data/test/dummy/app/models/elephant.rb +0 -3
  127. data/test/dummy/app/models/fluxor.rb +0 -3
  128. data/test/dummy/app/models/foo_habtm.rb +0 -5
  129. data/test/dummy/app/models/foo_widget.rb +0 -2
  130. data/test/dummy/app/models/fruit.rb +0 -5
  131. data/test/dummy/app/models/gadget.rb +0 -3
  132. data/test/dummy/app/models/kitchen/banana.rb +0 -5
  133. data/test/dummy/app/models/legacy_widget.rb +0 -4
  134. data/test/dummy/app/models/line_item.rb +0 -4
  135. data/test/dummy/app/models/not_on_update.rb +0 -4
  136. data/test/dummy/app/models/order.rb +0 -5
  137. data/test/dummy/app/models/paragraph.rb +0 -5
  138. data/test/dummy/app/models/person.rb +0 -38
  139. data/test/dummy/app/models/post.rb +0 -3
  140. data/test/dummy/app/models/post_with_status.rb +0 -8
  141. data/test/dummy/app/models/protected_widget.rb +0 -3
  142. data/test/dummy/app/models/quotation.rb +0 -5
  143. data/test/dummy/app/models/section.rb +0 -6
  144. data/test/dummy/app/models/skipper.rb +0 -6
  145. data/test/dummy/app/models/song.rb +0 -41
  146. data/test/dummy/app/models/thing.rb +0 -3
  147. data/test/dummy/app/models/translation.rb +0 -4
  148. data/test/dummy/app/models/truck.rb +0 -4
  149. data/test/dummy/app/models/vehicle.rb +0 -4
  150. data/test/dummy/app/models/whatchamajigger.rb +0 -4
  151. data/test/dummy/app/models/widget.rb +0 -16
  152. data/test/dummy/app/models/wotsit.rb +0 -8
  153. data/test/dummy/app/versions/custom_primary_key_record_version.rb +0 -3
  154. data/test/dummy/app/versions/joined_version.rb +0 -6
  155. data/test/dummy/app/versions/json_version.rb +0 -3
  156. data/test/dummy/app/versions/kitchen/banana_version.rb +0 -5
  157. data/test/dummy/app/versions/post_version.rb +0 -3
  158. data/test/dummy/app/views/layouts/application.html.erb +0 -14
  159. data/test/dummy/config.ru +0 -4
  160. data/test/dummy/config/application.rb +0 -80
  161. data/test/dummy/config/boot.rb +0 -10
  162. data/test/dummy/config/database.mysql.yml +0 -19
  163. data/test/dummy/config/database.postgres.yml +0 -15
  164. data/test/dummy/config/database.sqlite.yml +0 -15
  165. data/test/dummy/config/environment.rb +0 -5
  166. data/test/dummy/config/environments/development.rb +0 -41
  167. data/test/dummy/config/environments/production.rb +0 -74
  168. data/test/dummy/config/environments/test.rb +0 -51
  169. data/test/dummy/config/initializers/backtrace_silencers.rb +0 -9
  170. data/test/dummy/config/initializers/inflections.rb +0 -10
  171. data/test/dummy/config/initializers/mime_types.rb +0 -5
  172. data/test/dummy/config/initializers/paper_trail.rb +0 -9
  173. data/test/dummy/config/initializers/secret_token.rb +0 -9
  174. data/test/dummy/config/initializers/session_store.rb +0 -8
  175. data/test/dummy/config/locales/en.yml +0 -5
  176. data/test/dummy/config/routes.rb +0 -4
  177. data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +0 -361
  178. data/test/dummy/db/schema.rb +0 -288
  179. data/test/dummy/script/rails +0 -8
  180. data/test/functional/controller_test.rb +0 -90
  181. data/test/functional/enabled_for_controller_test.rb +0 -28
  182. data/test/functional/modular_sinatra_test.rb +0 -46
  183. data/test/functional/sinatra_test.rb +0 -51
  184. data/test/functional/thread_safety_test.rb +0 -46
  185. data/test/test_helper.rb +0 -127
  186. data/test/time_travel_helper.rb +0 -1
  187. data/test/unit/associations_test.rb +0 -1016
  188. data/test/unit/cleaner_test.rb +0 -188
  189. data/test/unit/inheritance_column_test.rb +0 -43
  190. data/test/unit/model_test.rb +0 -1489
  191. data/test/unit/protected_attrs_test.rb +0 -52
  192. data/test/unit/serializer_test.rb +0 -119
  193. data/test/unit/serializers/json_test.rb +0 -95
  194. data/test/unit/serializers/mixin_json_test.rb +0 -37
  195. data/test/unit/serializers/mixin_yaml_test.rb +0 -53
  196. data/test/unit/serializers/yaml_test.rb +0 -54
  197. data/test/unit/timestamp_test.rb +0 -41
  198. data/test/unit/version_test.rb +0 -119
@@ -1,51 +0,0 @@
1
- # PaperTrail is not compatible with sinatra 2 yet. Contributions welcome.
2
- if Gem::Version.new(Rack.release) < Gem::Version.new("2.0.0.alpha")
3
- require "test_helper"
4
- # require 'sinatra/main'
5
-
6
- # --- Tests for non-modular `Sinatra::Application` style ----
7
- module Sinatra
8
- class Application
9
- configs = YAML.load_file(File.expand_path("../../dummy/config/database.yml", __FILE__))
10
- ActiveRecord::Base.configurations = configs
11
- ActiveRecord::Base.establish_connection(:test)
12
-
13
- # We shouldn't actually need this line if I'm not mistaken but the tests
14
- # seem to fail without it ATM
15
- register PaperTrail::Sinatra
16
-
17
- get "/test" do
18
- Widget.create!(name: "bar")
19
- "Hai"
20
- end
21
-
22
- def current_user
23
- @current_user ||= OpenStruct.new(id: "raboof")
24
- end
25
- end
26
- end
27
-
28
- class SinatraTest < ActionDispatch::IntegrationTest
29
- include Rack::Test::Methods
30
-
31
- def app
32
- @app ||= Sinatra::Application
33
- end
34
-
35
- test "baseline" do
36
- assert_nil Widget.create.versions.first.whodunnit
37
- end
38
-
39
- context "`PaperTrail::Sinatra` in a `Sinatra::Application` application" do
40
- should "sets the `user_for_paper_trail` from the `current_user` method" do
41
- get "/test"
42
- assert_equal "Hai", last_response.body
43
- widget = Widget.last
44
- assert_not_nil widget
45
- assert_equal "bar", widget.name
46
- assert_equal 1, widget.versions.size
47
- assert_equal "raboof", widget.versions.first.whodunnit
48
- end
49
- end
50
- end
51
- end
@@ -1,46 +0,0 @@
1
- require "test_helper"
2
-
3
- class ThreadSafetyTest < ActionController::TestCase
4
- test "thread-safe when using #set_paper_trail_whodunnit" do
5
- blocked = true
6
-
7
- slow_thread = Thread.new do
8
- controller = TestController.new
9
- controller.send :set_paper_trail_whodunnit
10
- sleep 0.001 while blocked
11
- PaperTrail.whodunnit
12
- end
13
-
14
- fast_thread = Thread.new do
15
- controller = TestController.new
16
- controller.send :set_paper_trail_whodunnit
17
- who = PaperTrail.whodunnit
18
- blocked = false
19
- who
20
- end
21
-
22
- assert_not_equal slow_thread.value, fast_thread.value
23
- end
24
-
25
- test "thread-safe when using #without_versioning" do
26
- enabled = nil
27
-
28
- slow_thread = Thread.new do
29
- Widget.new.paper_trail.without_versioning do
30
- sleep(0.01)
31
- enabled = Widget.paper_trail.enabled?
32
- sleep(0.01)
33
- end
34
- enabled
35
- end
36
-
37
- fast_thread = Thread.new do
38
- sleep(0.005)
39
- Widget.paper_trail.enabled?
40
- end
41
-
42
- assert_not_equal slow_thread.value, fast_thread.value
43
- assert Widget.paper_trail.enabled?
44
- assert PaperTrail.enabled_for_model?(Widget)
45
- end
46
- end
@@ -1,127 +0,0 @@
1
- require "pry-nav"
2
-
3
- ENV["RAILS_ENV"] = "test"
4
- ENV["DB"] ||= "sqlite"
5
-
6
- unless File.exist?(File.expand_path("../../test/dummy/config/database.yml", __FILE__))
7
- warn "WARNING: No database.yml detected for the dummy app, please run `rake prepare` first"
8
- end
9
-
10
- def using_mysql?
11
- @using_mysql ||= ActiveRecord::Base.connection_config[:adapter].to_sym == :mysql2
12
- end
13
-
14
- require File.expand_path("../dummy/config/environment.rb", __FILE__)
15
- require "rails/test_help"
16
- require "shoulda"
17
- require "ffaker"
18
- require "database_cleaner"
19
-
20
- def active_record_gem_version
21
- Gem::Version.new(ActiveRecord::VERSION::STRING)
22
- end
23
-
24
- if active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
25
- # See https://github.com/rails/rails-controller-testing/issues/5
26
- ActionController::TestCase.send(:include, Rails::Controller::Testing::TestProcess)
27
- end
28
-
29
- Rails.backtrace_cleaner.remove_silencers!
30
-
31
- # Run any available migration
32
- ActiveRecord::Migrator.migrate File.expand_path("../dummy/db/migrate/", __FILE__)
33
-
34
- # Load support files
35
- Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
36
-
37
- # DatabaseCleaner is apparently necessary for doing proper transactions within MySQL (ugh)
38
- DatabaseCleaner.strategy = :truncation
39
-
40
- # global setup block resetting Thread.current
41
- module ActiveSupport
42
- class TestCase
43
- if using_mysql?
44
- if respond_to? :use_transactional_tests=
45
- self.use_transactional_tests = false
46
- else
47
- self.use_transactional_fixtures = false
48
- end
49
- setup { DatabaseCleaner.start }
50
- end
51
-
52
- teardown do
53
- DatabaseCleaner.clean if using_mysql?
54
- Thread.current[:paper_trail] = nil
55
- end
56
-
57
- private
58
-
59
- def assert_attributes_equal(expected, actual)
60
- if using_mysql?
61
- expected = expected.dup
62
- actual = actual.dup
63
-
64
- # Adjust timestamps for missing fractional seconds precision.
65
- %w(created_at updated_at).each do |timestamp|
66
- expected[timestamp] = expected[timestamp].change(usec: 0)
67
- actual[timestamp] = actual[timestamp].change(usec: 0)
68
- end
69
- end
70
-
71
- assert_equal expected, actual
72
- end
73
-
74
- def assert_changes_equal(expected, actual)
75
- if using_mysql?
76
- expected = expected.dup
77
- actual = actual.dup
78
-
79
- # Adjust timestamps for missing fractional seconds precision.
80
- %w(created_at updated_at).each do |timestamp|
81
- expected[timestamp][1] = expected[timestamp][1].change(usec: 0)
82
- actual[timestamp][1] = actual[timestamp][1].change(usec: 0)
83
- end
84
- end
85
-
86
- assert_equal expected, actual
87
- end
88
- end
89
- end
90
-
91
- #
92
- # Helpers
93
- #
94
-
95
- def change_schema
96
- ActiveRecord::Migration.verbose = false
97
- ActiveRecord::Schema.define do
98
- add_column :versions, :custom_created_at, :datetime
99
- end
100
- ActiveRecord::Migration.verbose = true
101
- reset_version_class_column_info!
102
- end
103
-
104
- # Wrap args in a hash to support the ActionController::TestCase and
105
- # ActionDispatch::Integration HTTP request method switch to keyword args
106
- # (see https://github.com/rails/rails/blob/master/actionpack/CHANGELOG.md)
107
- def params_wrapper(args)
108
- if defined?(::Rails) && active_record_gem_version >= Gem::Version.new("5.0.0.beta1")
109
- { params: args }
110
- else
111
- args
112
- end
113
- end
114
-
115
- def reset_version_class_column_info!
116
- PaperTrail::Version.connection.schema_cache.clear!
117
- PaperTrail::Version.reset_column_information
118
- end
119
-
120
- def restore_schema
121
- ActiveRecord::Migration.verbose = false
122
- ActiveRecord::Schema.define do
123
- remove_column :versions, :custom_created_at
124
- end
125
- ActiveRecord::Migration.verbose = true
126
- reset_version_class_column_info!
127
- end
@@ -1 +0,0 @@
1
- require "timecop"
@@ -1,1016 +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 { @widget_0 = @widget.versions.last.reify(has_one: true) }
47
-
48
- should "see the associated as it was at the time" do
49
- assert_nil @widget_0.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 { @widget_0 = @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", @widget_0.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 { @widget_1 = @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", @widget_1.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 { @widget_1 = @widget.versions.last.reify(has_one: false) }
100
-
101
- should "see the associated as it is live" do
102
- assert_equal "wotsit_3", @widget_1.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 { @widget_1 = @widget.versions.last.reify(has_one: true) }
114
-
115
- should "see the associated as it was at the time" do
116
- assert_equal @wotsit, @widget_1.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 { @widget_2 = @widget.versions.last.reify(has_one: true) }
132
-
133
- should "see the associated as it was at the time" do
134
- assert_nil @widget_2.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 { @customer_0 = @customer.versions.last.reify(has_many: true) }
153
-
154
- should "see the associated as it was at the time" do
155
- assert_equal [], @customer_0.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
- @customer_0 = @customer.versions.last.reify(
166
- has_many: true,
167
- mark_for_destruction: true
168
- )
169
- assert_equal [true], @customer_0.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 { @customer_0 = @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"], @customer_0.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 { @customer_0 = @customer.versions.last.reify(has_many: true) }
196
-
197
- should "see the live version of the nested association" do
198
- assert_equal ["product_0"], @customer_0.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 { @customer_1 = @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"], @customer_1.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 { @customer_1 = @customer.versions.last.reify(has_many: false) }
226
-
227
- should "see the associated as it is live" do
228
- assert_equal ["order_date_3"], @customer_1.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 { @customer_1 = @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"], @customer_1.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 { @customer_1 = @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], @customer_1.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 { @customer_1 = @customer.versions.last.reify(has_many: true) }
278
-
279
- should "see the associated as it was at the time" do
280
- assert_equal [], @customer_1.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 { @customer_0 = @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"], @customer_0.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
- @customer_0 = @customer.versions.last.reify(
306
- has_many: true,
307
- mark_for_destruction: true
308
- )
309
- assert @customer_0.
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 { @book_0 = @book.versions.last.reify(has_many: true) }
331
-
332
- should "see the associated as it was at the time" do
333
- assert_equal [], @book_0.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
- @book_0 = @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], @book_0.authors.map(&:marked_for_destruction?)
351
- end
352
-
353
- should "mark the associated-through for destruction" do
354
- assert_equal [true], @book_0.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
- @book_0 = @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 [], @book_0.authors
374
- end
375
- end
376
-
377
- context "when reified with option mark_for_destruction" do
378
- setup do
379
- @book_0 = @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], @book_0.authors.map(&:marked_for_destruction?)
387
- end
388
-
389
- should "mark the associated-through for destruction" do
390
- assert_equal [true], @book_0.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 { @book_0 = @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"], @book_0.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 { @book_1 = @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"], @book_1.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 { @book_1 = @book.versions.last.reify(has_many: false) }
434
-
435
- should "see the associated as it is live" do
436
- assert_equal ["author_3"], @book_1.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 { @book_1 = @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], @book_1.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 { @book_1 = @book.versions.last.reify(has_many: true) }
468
-
469
- should "see the associated as it was at the time" do
470
- assert_equal [], @book_1.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 { @book_1 = @book.versions.last.reify(has_many: true) }
484
-
485
- should "see the associated as it was at the time" do
486
- assert_equal [], @book_1.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 { @book_0 = @book.versions.last.reify(has_many: true) }
498
-
499
- should "only see the first associated" do
500
- assert_equal ["author_0"], @book_0.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
- @book_0 = @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 @book_0.
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 @book_0.
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 { @book_0 = @book.versions.last.reify(has_many: true) }
539
-
540
- should "only see the first associated" do
541
- assert_equal ["author_0"], @book_0.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
- @book_0 = @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 !@book_0.
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 @book_0.
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 { @book_0 = @book.versions.last.reify(has_many: true) }
582
-
583
- should "see the live association" do
584
- assert_equal ["editor_0"], @book_0.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 { @wotsit_0 = @wotsit.versions.last.reify(belongs_to: true) }
786
-
787
- should "see the associated as it was at the time" do
788
- assert_equal nil, @wotsit_0.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 { @wotsit_1 = @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", @wotsit_1.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 { @wotsit_1 = @wotsit.versions.last.reify(belongs_to: false) }
819
-
820
- should "see the associated as it is live" do
821
- assert_equal "widget_3", @wotsit_1.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" do
833
- setup { @wotsit_2 = @wotsit.versions.last.reify(belongs_to: true) }
834
-
835
- should "see the associated as it was at the time" do
836
- assert_equal @widget, @wotsit_2.widget
837
- end
838
-
839
- should "not persist changes to the live association" do
840
- assert_nil @wotsit.reload.widget
841
- end
842
- end
843
-
844
- context "and then the model is updated" do
845
- setup do
846
- Timecop.travel 1.second.since
847
- @wotsit.update_attributes name: "wotsit_3"
848
- end
849
-
850
- context "when reified" do
851
- setup { @wotsit_2 = @wotsit.versions.last.reify(belongs_to: true) }
852
-
853
- should "see the associated as it was the time" do
854
- assert_nil @wotsit_2.widget
855
- end
856
- end
857
- end
858
- end
859
- end
860
-
861
- context "where the association is changed between model versions" do
862
- setup do
863
- @wotsit = @widget.create_wotsit(name: "wotsit_0")
864
- Timecop.travel 1.second.since
865
- @new_widget = Widget.create(name: "new_widget")
866
- @wotsit.update_attributes(widget_id: @new_widget.id, name: "wotsit_1")
867
- end
868
-
869
- context "when reified" do
870
- setup { @wotsit_0 = @wotsit.versions.last.reify(belongs_to: true) }
871
-
872
- should "see the association as it was at the time" do
873
- assert_equal "widget_0", @wotsit_0.widget.name
874
- end
875
-
876
- should "not persist changes to the live association" do
877
- assert_equal @new_widget, @wotsit.reload.widget
878
- end
879
- end
880
-
881
- context "when reified with option mark_for_destruction" do
882
- setup do
883
- @wotsit_0 = @wotsit.versions.last.
884
- reify(belongs_to: true, mark_for_destruction: true)
885
- end
886
-
887
- should "should not mark the new associated for destruction" do
888
- assert_equal false, @new_widget.marked_for_destruction?
889
- end
890
- end
891
- end
892
- end
893
- end
894
-
895
- context "has_and_belongs_to_many associations" do
896
- context "foo and bar" do
897
- setup do
898
- @foo = FooHabtm.create(name: "foo")
899
- Timecop.travel 1.second.since
900
- end
901
-
902
- context "where the association is created between model versions" do
903
- setup do
904
- @foo.update_attributes(name: "foo1", bar_habtms: [BarHabtm.create(name: "bar")])
905
- end
906
-
907
- context "when reified" do
908
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
909
-
910
- should "see the associated as it was at the time" do
911
- assert_equal 0, @reified.bar_habtms.length
912
- end
913
-
914
- should "not persist changes to the live association" do
915
- assert_not_equal @reified.bar_habtms, @foo.reload.bar_habtms
916
- end
917
- end
918
- end
919
-
920
- context "where the association is changed between model versions" do
921
- setup do
922
- @foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
923
- Timecop.travel 1.second.since
924
- @foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar3")])
925
- end
926
-
927
- context "when reified" do
928
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
929
-
930
- should "see the association as it was at the time" do
931
- assert_equal "bar2", @reified.bar_habtms.first.name
932
- end
933
-
934
- should "not persist changes to the live association" do
935
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
936
- end
937
- end
938
-
939
- context "when reified with has_and_belongs_to_many: false" do
940
- setup { @reified = @foo.versions.last.reify }
941
-
942
- should "see the association as it is now" do
943
- assert_equal "bar3", @reified.bar_habtms.first.name
944
- end
945
- end
946
- end
947
-
948
- context "where the association is destroyed between model versions" do
949
- setup do
950
- @foo.update_attributes(name: "foo2", bar_habtms: [BarHabtm.create(name: "bar2")])
951
- Timecop.travel 1.second.since
952
- @foo.update_attributes(name: "foo3", bar_habtms: [])
953
- end
954
-
955
- context "when reified" do
956
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
957
-
958
- should "see the association as it was at the time" do
959
- assert_equal "bar2", @reified.bar_habtms.first.name
960
- end
961
-
962
- should "not persist changes to the live association" do
963
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
964
- end
965
- end
966
- end
967
-
968
- context "where the unassociated model changes" do
969
- setup do
970
- @bar = BarHabtm.create(name: "bar2")
971
- @foo.update_attributes(name: "foo2", bar_habtms: [@bar])
972
- Timecop.travel 1.second.since
973
- @foo.update_attributes(name: "foo3", bar_habtms: [BarHabtm.create(name: "bar4")])
974
- Timecop.travel 1.second.since
975
- @bar.update_attributes(name: "bar3")
976
- end
977
-
978
- context "when reified" do
979
- setup { @reified = @foo.versions.last.reify(has_and_belongs_to_many: true) }
980
-
981
- should "see the association as it was at the time" do
982
- assert_equal "bar2", @reified.bar_habtms.first.name
983
- end
984
-
985
- should "not persist changes to the live association" do
986
- assert_not_equal @reified.bar_habtms.first, @foo.reload.bar_habtms.first
987
- end
988
- end
989
- end
990
- end
991
-
992
- context "updated via nested attributes" do
993
- setup do
994
- @foo = FooHabtm.create(
995
- name: "foo",
996
- bar_habtms_attributes: [{ name: "bar" }]
997
- )
998
- Timecop.travel 1.second.since
999
- @foo.update_attributes(
1000
- name: "foo2",
1001
- bar_habtms_attributes: [{ id: @foo.bar_habtms.first.id, name: "bar2" }]
1002
- )
1003
-
1004
- @reified = @foo.versions.last.reify(has_and_belongs_to_many: true)
1005
- end
1006
-
1007
- should "see the associated object as it was at the time" do
1008
- assert_equal "bar", @reified.bar_habtms.first.name
1009
- end
1010
-
1011
- should "not persist changes to the live object" do
1012
- assert_not_equal @reified.bar_habtms.first.name, @foo.reload.bar_habtms.first.name
1013
- end
1014
- end
1015
- end
1016
- end