paper_trail 5.2.3 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -74,8 +74,8 @@ module PaperTrail
74
74
  return where(arel_table[primary_key].gt(obj.id)).order(arel_table[primary_key].asc)
75
75
  end
76
76
 
77
- obj = obj.send(PaperTrail.timestamp_field) if obj.is_a?(self)
78
- where(arel_table[PaperTrail.timestamp_field].gt(obj)).order(timestamp_sort_order)
77
+ obj = obj.send(:created_at) if obj.is_a?(self)
78
+ where(arel_table[:created_at].gt(obj)).order(timestamp_sort_order)
79
79
  end
80
80
 
81
81
  # Returns versions before `obj`.
@@ -90,22 +90,22 @@ module PaperTrail
90
90
  return where(arel_table[primary_key].lt(obj.id)).order(arel_table[primary_key].desc)
91
91
  end
92
92
 
93
- obj = obj.send(PaperTrail.timestamp_field) if obj.is_a?(self)
94
- where(arel_table[PaperTrail.timestamp_field].lt(obj)).
93
+ obj = obj.send(:created_at) if obj.is_a?(self)
94
+ where(arel_table[:created_at].lt(obj)).
95
95
  order(timestamp_sort_order("desc"))
96
96
  end
97
97
 
98
98
  def between(start_time, end_time)
99
99
  where(
100
- arel_table[PaperTrail.timestamp_field].gt(start_time).
101
- and(arel_table[PaperTrail.timestamp_field].lt(end_time))
100
+ arel_table[:created_at].gt(start_time).
101
+ and(arel_table[:created_at].lt(end_time))
102
102
  ).order(timestamp_sort_order)
103
103
  end
104
104
 
105
105
  # Defaults to using the primary key as the secondary sort order if
106
106
  # possible.
107
107
  def timestamp_sort_order(direction = "asc")
108
- [arel_table[PaperTrail.timestamp_field].send(direction.downcase)].tap do |array|
108
+ [arel_table[:created_at].send(direction.downcase)].tap do |array|
109
109
  array << arel_table[primary_key].send(direction.downcase) if primary_key_is_int?
110
110
  end
111
111
  end
@@ -1,9 +1,9 @@
1
1
  module PaperTrail
2
2
  # :nodoc:
3
3
  module VERSION
4
- MAJOR = 5
5
- MINOR = 2
6
- TINY = 3
4
+ MAJOR = 6
5
+ MINOR = 0
6
+ TINY = 0
7
7
  PRE = nil
8
8
 
9
9
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".").freeze
data/lib/paper_trail.rb CHANGED
@@ -72,21 +72,12 @@ module PaperTrail
72
72
 
73
73
  # Set the field which records when a version was created.
74
74
  # @api public
75
- # @deprecated
76
- def timestamp_field=(field_name)
77
- ::ActiveSupport::Deprecation.warn(
78
- "PaperTrail.timestamp_field= is deprecated without replacement." \
79
- "See https://github.com/airblade/paper_trail/pull/861 for discussion",
80
- caller(1)
75
+ def timestamp_field=(_field_name)
76
+ raise(
77
+ "PaperTrail.timestamp_field= has been removed, without replacement. " \
78
+ "It is no longer configurable. The timestamp field in the versions table " \
79
+ "must now be named created_at."
81
80
  )
82
- PaperTrail.config.timestamp_field = field_name
83
- end
84
-
85
- # Returns the field which records when a version was created.
86
- # @api public
87
- # @deprecated
88
- def timestamp_field
89
- PaperTrail.config.timestamp_field
90
81
  end
91
82
 
92
83
  # Sets who is responsible for any changes that occur. You would normally use
data/paper_trail.gemspec CHANGED
@@ -20,7 +20,8 @@ Gem::Specification.new do |s|
20
20
  s.required_rubygems_version = ">= 1.3.6"
21
21
  s.required_ruby_version = ">= 1.9.3"
22
22
 
23
- s.add_dependency "activerecord", [">= 3.0", "< 6.0"]
23
+ # Rails does not follow semver, makes breaking changes in minor versions.
24
+ s.add_dependency "activerecord", [">= 4.0", "< 5.2"]
24
25
  s.add_dependency "request_store", "~> 1.1"
25
26
 
26
27
  s.add_development_dependency "appraisal", "~> 2.1"
@@ -14,13 +14,28 @@ describe Widget, type: :model do
14
14
  widget.update_attributes!(name: "Bob")
15
15
  end
16
16
 
17
- it "is possible to do assertions on versions" do
17
+ it "is possible to do assertions on version attributes" do
18
18
  expect(widget).to have_a_version_with name: "Leonard", an_integer: 1
19
19
  expect(widget).to have_a_version_with an_integer: 1
20
20
  expect(widget).to have_a_version_with name: "Tom"
21
21
  end
22
22
  end
23
23
 
24
+ describe "`have_a_version_with_changes` matcher", versioning: true do
25
+ before do
26
+ widget.update_attributes!(name: "Leonard", an_integer: 2)
27
+ widget.update_attributes!(name: "Tom")
28
+ widget.update_attributes!(name: "Bob")
29
+ end
30
+
31
+ it "is possible to do assertions on version changes" do
32
+ expect(widget).to have_a_version_with_changes name: "Leonard", an_integer: 2
33
+ expect(widget).to have_a_version_with_changes an_integer: 2
34
+ expect(widget).to have_a_version_with_changes name: "Tom"
35
+ expect(widget).to have_a_version_with_changes name: "Bob"
36
+ end
37
+ end
38
+
24
39
  describe "versioning option" do
25
40
  context "enabled", versioning: true do
26
41
  it "should enable versioning" do
@@ -238,8 +253,6 @@ describe Widget, type: :model do
238
253
  end
239
254
 
240
255
  describe "#whodunnit" do
241
- it { is_expected.to respond_to(:whodunnit) }
242
-
243
256
  context "no block given" do
244
257
  it "should raise an error" do
245
258
  expect {
@@ -1,7 +1,6 @@
1
1
  # Example from 'Overwriting default accessors' in ActiveRecord::Base.
2
2
  class Song < ActiveRecord::Base
3
3
  has_paper_trail
4
- attr_accessor :name
5
4
 
6
5
  # Uses an integer of seconds to hold the length of the song
7
6
  def length=(minutes)
@@ -12,30 +11,36 @@ class Song < ActiveRecord::Base
12
11
  read_attribute(:length) / 60
13
12
  end
14
13
 
15
- # override attributes hashes like some libraries do
16
- def attributes_with_name
17
- if name
18
- attributes_without_name.merge(name: name)
19
- else
20
- attributes_without_name
14
+ if ActiveRecord::VERSION::MAJOR >= 5
15
+ attribute :name, :string
16
+ else
17
+ attr_accessor :name
18
+
19
+ # override attributes hashes like some libraries do
20
+ def attributes_with_name
21
+ if name
22
+ attributes_without_name.merge(name: name)
23
+ else
24
+ attributes_without_name
25
+ end
21
26
  end
22
- end
23
27
 
24
- # `alias_method_chain` is deprecated in rails 5, but we cannot use the
25
- # suggested replacement, `Module#prepend`, because we still support ruby 1.9.
26
- alias attributes_without_name attributes
27
- alias attributes attributes_with_name
28
+ # `alias_method_chain` is deprecated in rails 5, but we cannot use the
29
+ # suggested replacement, `Module#prepend`, because we still support ruby 1.9.
30
+ alias attributes_without_name attributes
31
+ alias attributes attributes_with_name
28
32
 
29
- def changed_attributes_with_name
30
- if name
31
- changed_attributes_without_name.merge(name: name)
32
- else
33
- changed_attributes_without_name
33
+ def changed_attributes_with_name
34
+ if name
35
+ changed_attributes_without_name.merge(name: name)
36
+ else
37
+ changed_attributes_without_name
38
+ end
34
39
  end
35
- end
36
40
 
37
- # `alias_method_chain` is deprecated in rails 5, but we cannot use the
38
- # suggested replacement, `Module#prepend`, because we still support ruby 1.9.
39
- alias changed_attributes_without_name changed_attributes
40
- alias changed_attributes changed_attributes_with_name
41
+ # `alias_method_chain` is deprecated in rails 5, but we cannot use the
42
+ # suggested replacement, `Module#prepend`, because we still support ruby 1.9.
43
+ alias changed_attributes_without_name changed_attributes
44
+ alias changed_attributes changed_attributes_with_name
45
+ end
41
46
  end
data/test/test_helper.rb CHANGED
@@ -88,19 +88,6 @@ module ActiveSupport
88
88
  end
89
89
  end
90
90
 
91
- #
92
- # Helpers
93
- #
94
-
95
- def change_schema
96
- ActiveRecord::Migration.verbose = false
97
- ActiveRecord::Schema.define do
98
- add_column :versions, :custom_created_at, :datetime
99
- end
100
- ActiveRecord::Migration.verbose = true
101
- reset_version_class_column_info!
102
- end
103
-
104
91
  # Wrap args in a hash to support the ActionController::TestCase and
105
92
  # ActionDispatch::Integration HTTP request method switch to keyword args
106
93
  # (see https://github.com/rails/rails/blob/master/actionpack/CHANGELOG.md)
@@ -112,16 +99,27 @@ def params_wrapper(args)
112
99
  end
113
100
  end
114
101
 
115
- def reset_version_class_column_info!
116
- PaperTrail::Version.connection.schema_cache.clear!
117
- PaperTrail::Version.reset_column_information
118
- end
102
+ module CleanupCallbacks
103
+ def cleanup_callbacks(target, type)
104
+ original_callbacks = nil
119
105
 
120
- def restore_schema
121
- ActiveRecord::Migration.verbose = false
122
- ActiveRecord::Schema.define do
123
- remove_column :versions, :custom_created_at
106
+ setup do
107
+ if ActiveRecord::VERSION::MAJOR > 3
108
+ original_callbacks = target.send(:get_callbacks, type).deep_dup
109
+ else
110
+ # While this defeats the purpose of targeted callback
111
+ # cleanup, callbacks were incredibly difficult to modify
112
+ # prior to Rails 4, and Rails internal callbacks were only
113
+ # used for autosaving associations in Rails 3. Our tests
114
+ # don't care whether a Fluxor's widget is autosaved.
115
+ target.reset_callbacks(type)
116
+ end
117
+ end
118
+
119
+ teardown do
120
+ if original_callbacks
121
+ target.send(:set_callbacks, type, original_callbacks)
122
+ end
123
+ end
124
124
  end
125
- ActiveRecord::Migration.verbose = true
126
- reset_version_class_column_info!
127
125
  end
@@ -785,7 +785,7 @@ class AssociationsTest < ActiveSupport::TestCase
785
785
  setup { @wotsit_0 = @wotsit.versions.last.reify(belongs_to: true) }
786
786
 
787
787
  should "see the associated as it was at the time" do
788
- assert_equal nil, @wotsit_0.widget
788
+ assert_nil @wotsit_0.widget
789
789
  end
790
790
 
791
791
  should "not persist changes to the live association" do
@@ -148,41 +148,4 @@ class PaperTrailCleanerTest < ActiveSupport::TestCase
148
148
  end
149
149
  end
150
150
  end # clean_versions! method
151
-
152
- context "Custom timestamp field" do
153
- setup do
154
- change_schema
155
- populate_db!
156
- # now mess with the timestamps
157
- @animals.each do |animal|
158
- animal.versions.reverse.each_with_index do |version, index|
159
- version.update_attribute(:custom_created_at, Time.now.utc + index.days)
160
- end
161
- end
162
- PaperTrail.timestamp_field = :custom_created_at
163
- @animals.map { |a| a.versions.reload } # reload the `versions` association for each animal
164
- end
165
-
166
- teardown do
167
- PaperTrail.timestamp_field = :created_at
168
- restore_schema
169
- end
170
-
171
- should "Baseline" do
172
- assert_equal 9, PaperTrail::Version.count
173
- @animals.each do |animal|
174
- assert_equal 3, animal.versions.size
175
- animal.versions.each_cons(2) do |a, b|
176
- assert_equal a.created_at.to_date, b.created_at.to_date
177
- assert_not_equal a.custom_created_at.to_date, b.custom_created_at.to_date
178
- end
179
- end
180
- end
181
-
182
- should "group by `PaperTrail.timestamp_field` when seperating the versions by date to clean" do
183
- assert_equal 9, PaperTrail::Version.count
184
- PaperTrail.clean_versions!
185
- assert_equal 9, PaperTrail::Version.count
186
- end
187
- end
188
151
  end
@@ -27,14 +27,12 @@ class InheritanceColumnTest < ActiveSupport::TestCase
27
27
 
28
28
  # For some reason `@dog.versions` doesn't include the final `destroy` version.
29
29
  # Neither do `@dog.versions.scoped` nor `@dog.versions(true)` nor `@dog.versions.reload`.
30
- dog_versions = PaperTrail::Version.where(item_id: @dog.id).
31
- order(PaperTrail.timestamp_field)
30
+ dog_versions = PaperTrail::Version.where(item_id: @dog.id).order(:created_at)
32
31
  assert_equal 4, dog_versions.count
33
32
  assert_nil dog_versions.first.reify
34
33
  assert_equal %w(NilClass Dog Dog Dog), dog_versions.map { |v| v.reify.class.name }
35
34
 
36
- cat_versions = PaperTrail::Version.where(item_id: @cat.id).
37
- order(PaperTrail.timestamp_field)
35
+ cat_versions = PaperTrail::Version.where(item_id: @cat.id).order(:created_at)
38
36
  assert_equal 4, cat_versions.count
39
37
  assert_nil cat_versions.first.reify
40
38
  assert_equal %w(NilClass Cat Cat Cat), cat_versions.map { |v| v.reify.class.name }
@@ -2,6 +2,8 @@ require "test_helper"
2
2
  require "time_travel_helper"
3
3
 
4
4
  class HasPaperTrailModelTest < ActiveSupport::TestCase
5
+ extend CleanupCallbacks
6
+
5
7
  context "A record with defined 'only' and 'ignore' attributes" do
6
8
  setup { @article = Article.create }
7
9
 
@@ -135,7 +137,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
135
137
  end
136
138
 
137
139
  should "have removed the skipped attributes when saving the previous version" do
138
- assert_equal nil, PaperTrail.serializer.load(@old_article.object)["file_upload"]
140
+ assert_nil PaperTrail.serializer.load(@old_article.object)["file_upload"]
139
141
  end
140
142
 
141
143
  should "have kept the non-skipped attributes in the previous version" do
@@ -517,16 +519,9 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
517
519
 
518
520
  context "after a column is removed from the record's schema" do
519
521
  setup do
520
- change_schema
521
- Widget.connection.schema_cache.clear!
522
- Widget.reset_column_information
523
522
  @last = @widget.versions.last
524
523
  end
525
524
 
526
- teardown do
527
- restore_schema
528
- end
529
-
530
525
  should "reify previous version" do
531
526
  assert_kind_of Widget, @last.reify
532
527
  end
@@ -1291,6 +1286,11 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1291
1286
 
1292
1287
  context "The `on` option" do
1293
1288
  context "on create" do
1289
+ cleanup_callbacks(Fluxor, :create)
1290
+ cleanup_callbacks(Fluxor, :update)
1291
+ cleanup_callbacks(Fluxor, :destroy)
1292
+ cleanup_callbacks(Fluxor, :save)
1293
+
1294
1294
  setup do
1295
1295
  Fluxor.instance_eval <<-END
1296
1296
  has_paper_trail :on => [:create]
@@ -1299,16 +1299,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1299
1299
  @fluxor.update_attributes name: "blah"
1300
1300
  @fluxor.destroy
1301
1301
  end
1302
+
1302
1303
  should "only have a version for the create event" do
1303
1304
  assert_equal 1, @fluxor.versions.length
1304
1305
  assert_equal "create", @fluxor.versions.last.event
1305
1306
  end
1306
1307
  end
1308
+
1307
1309
  context "on update" do
1310
+ cleanup_callbacks(Fluxor, :create)
1311
+ cleanup_callbacks(Fluxor, :update)
1312
+ cleanup_callbacks(Fluxor, :destroy)
1313
+ cleanup_callbacks(Fluxor, :save)
1314
+
1308
1315
  setup do
1309
- Fluxor.reset_callbacks :create
1310
- Fluxor.reset_callbacks :update
1311
- Fluxor.reset_callbacks :destroy
1312
1316
  Fluxor.instance_eval <<-END
1313
1317
  has_paper_trail :on => [:update]
1314
1318
  END
@@ -1316,16 +1320,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1316
1320
  @fluxor.update_attributes name: "blah"
1317
1321
  @fluxor.destroy
1318
1322
  end
1323
+
1319
1324
  should "only have a version for the update event" do
1320
1325
  assert_equal 1, @fluxor.versions.length
1321
1326
  assert_equal "update", @fluxor.versions.last.event
1322
1327
  end
1323
1328
  end
1329
+
1324
1330
  context "on destroy" do
1331
+ cleanup_callbacks(Fluxor, :create)
1332
+ cleanup_callbacks(Fluxor, :update)
1333
+ cleanup_callbacks(Fluxor, :destroy)
1334
+ cleanup_callbacks(Fluxor, :save)
1335
+
1325
1336
  setup do
1326
- Fluxor.reset_callbacks :create
1327
- Fluxor.reset_callbacks :update
1328
- Fluxor.reset_callbacks :destroy
1329
1337
  Fluxor.instance_eval <<-END
1330
1338
  has_paper_trail :on => [:destroy]
1331
1339
  END
@@ -1333,16 +1341,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1333
1341
  @fluxor.update_attributes name: "blah"
1334
1342
  @fluxor.destroy
1335
1343
  end
1344
+
1336
1345
  should "only have a version for the destroy event" do
1337
1346
  assert_equal 1, @fluxor.versions.length
1338
1347
  assert_equal "destroy", @fluxor.versions.last.event
1339
1348
  end
1340
1349
  end
1350
+
1341
1351
  context "on []" do
1352
+ cleanup_callbacks(Fluxor, :create)
1353
+ cleanup_callbacks(Fluxor, :update)
1354
+ cleanup_callbacks(Fluxor, :destroy)
1355
+ cleanup_callbacks(Fluxor, :save)
1356
+
1342
1357
  setup do
1343
- Fluxor.reset_callbacks :create
1344
- Fluxor.reset_callbacks :update
1345
- Fluxor.reset_callbacks :destroy
1346
1358
  Fluxor.instance_eval <<-END
1347
1359
  has_paper_trail :on => []
1348
1360
  END
@@ -1363,11 +1375,14 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1363
1375
  assert_equal 1, @fluxor.versions.length
1364
1376
  end
1365
1377
  end
1378
+
1366
1379
  context "allows a symbol to be passed" do
1380
+ cleanup_callbacks(Fluxor, :create)
1381
+ cleanup_callbacks(Fluxor, :update)
1382
+ cleanup_callbacks(Fluxor, :destroy)
1383
+ cleanup_callbacks(Fluxor, :save)
1384
+
1367
1385
  setup do
1368
- Fluxor.reset_callbacks :create
1369
- Fluxor.reset_callbacks :update
1370
- Fluxor.reset_callbacks :destroy
1371
1386
  Fluxor.instance_eval <<-END
1372
1387
  has_paper_trail :on => :create
1373
1388
  END
@@ -1375,6 +1390,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1375
1390
  @fluxor.update_attributes name: "blah"
1376
1391
  @fluxor.destroy
1377
1392
  end
1393
+
1378
1394
  should "only have a version for hte create event" do
1379
1395
  assert_equal 1, @fluxor.versions.length
1380
1396
  assert_equal "create", @fluxor.versions.last.event
@@ -1420,10 +1436,12 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1420
1436
 
1421
1437
  context "custom events" do
1422
1438
  context "on create" do
1439
+ cleanup_callbacks(Fluxor, :create)
1440
+ cleanup_callbacks(Fluxor, :update)
1441
+ cleanup_callbacks(Fluxor, :destroy)
1442
+ cleanup_callbacks(Fluxor, :save)
1443
+
1423
1444
  setup do
1424
- Fluxor.reset_callbacks :create
1425
- Fluxor.reset_callbacks :update
1426
- Fluxor.reset_callbacks :destroy
1427
1445
  Fluxor.instance_eval <<-END
1428
1446
  has_paper_trail :on => [:create]
1429
1447
  END
@@ -1431,16 +1449,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1431
1449
  @fluxor.update_attributes name: "blah"
1432
1450
  @fluxor.destroy
1433
1451
  end
1452
+
1434
1453
  should "only have a version for the created event" do
1435
1454
  assert_equal 1, @fluxor.versions.length
1436
1455
  assert_equal "created", @fluxor.versions.last.event
1437
1456
  end
1438
1457
  end
1458
+
1439
1459
  context "on update" do
1460
+ cleanup_callbacks(Fluxor, :create)
1461
+ cleanup_callbacks(Fluxor, :update)
1462
+ cleanup_callbacks(Fluxor, :destroy)
1463
+ cleanup_callbacks(Fluxor, :save)
1464
+
1440
1465
  setup do
1441
- Fluxor.reset_callbacks :create
1442
- Fluxor.reset_callbacks :update
1443
- Fluxor.reset_callbacks :destroy
1444
1466
  Fluxor.instance_eval <<-END
1445
1467
  has_paper_trail :on => [:update]
1446
1468
  END
@@ -1448,16 +1470,20 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1448
1470
  @fluxor.update_attributes name: "blah"
1449
1471
  @fluxor.destroy
1450
1472
  end
1473
+
1451
1474
  should "only have a version for the name_updated event" do
1452
1475
  assert_equal 1, @fluxor.versions.length
1453
1476
  assert_equal "name_updated", @fluxor.versions.last.event
1454
1477
  end
1455
1478
  end
1479
+
1456
1480
  context "on destroy" do
1481
+ cleanup_callbacks(Fluxor, :create)
1482
+ cleanup_callbacks(Fluxor, :update)
1483
+ cleanup_callbacks(Fluxor, :destroy)
1484
+ cleanup_callbacks(Fluxor, :save)
1485
+
1457
1486
  setup do
1458
- Fluxor.reset_callbacks :create
1459
- Fluxor.reset_callbacks :update
1460
- Fluxor.reset_callbacks :destroy
1461
1487
  Fluxor.instance_eval <<-END
1462
1488
  has_paper_trail :on => [:destroy]
1463
1489
  END
@@ -1465,6 +1491,7 @@ class HasPaperTrailModelTest < ActiveSupport::TestCase
1465
1491
  @fluxor.update_attributes name: "blah"
1466
1492
  @fluxor.destroy
1467
1493
  end
1494
+
1468
1495
  should "only have a version for the destroy event" do
1469
1496
  assert_equal 1, @fluxor.versions.length
1470
1497
  assert_equal "destroyed", @fluxor.versions.last.event