paper_trail 4.0.0 → 5.1.0

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