paper_trail 5.1.1 → 5.2.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.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +9 -7
- data/.rubocop.yml +0 -4
- data/.rubocop_todo.yml +6 -1
- data/CHANGELOG.md +41 -1
- data/README.md +45 -43
- data/lib/paper_trail.rb +5 -0
- data/lib/paper_trail/attribute_serializers/object_attribute.rb +1 -1
- data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +1 -1
- data/lib/paper_trail/frameworks/rails/controller.rb +7 -2
- data/lib/paper_trail/has_paper_trail.rb +196 -495
- data/lib/paper_trail/model_config.rb +195 -0
- data/lib/paper_trail/record_trail.rb +450 -0
- data/lib/paper_trail/reifier.rb +11 -11
- data/lib/paper_trail/version_number.rb +2 -2
- data/spec/models/boolit_spec.rb +2 -2
- data/spec/models/fluxor_spec.rb +4 -6
- data/spec/models/gadget_spec.rb +5 -7
- data/spec/models/not_on_update_spec.rb +2 -2
- data/spec/models/post_with_status_spec.rb +1 -1
- data/spec/models/widget_spec.rb +36 -66
- data/test/dummy/app/models/callback_modifier.rb +5 -5
- data/test/dummy/app/models/elephant.rb +1 -1
- data/test/functional/thread_safety_test.rb +4 -4
- data/test/unit/cleaner_test.rb +1 -1
- data/test/unit/model_test.rb +58 -48
- data/test/unit/protected_attrs_test.rb +4 -3
- data/test/unit/serializer_test.rb +4 -3
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1e5022690b85795b9f9d1543b34bcb2dc09cf7c1
|
4
|
+
data.tar.gz: 791c6da3f8bbe7da599f14814428cf4c038a6c11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 97f5979d33a1f66ac7987981db9271ef2e6f2c746447eba32272ca5d3b564d5134166ad8434e6149824af6c1f048d447d8f136e9060ff64ff02fbdc34c6f975a
|
7
|
+
data.tar.gz: 33aa6d09d85870ec8bd1c34f71b2249f5dbb84651bb192fef2c2c57f4a4f3cbc569cb74869214926cc5038769d632dedddaafa9c858adbbb83b6911d4c5d71e6
|
data/.github/CONTRIBUTING.md
CHANGED
@@ -92,14 +92,16 @@ DB=postgres bundle exec rake
|
|
92
92
|
|
93
93
|
1. Set the version in lib/paper_trail/version_number.rb
|
94
94
|
- Set PRE to nil unless it's a pre-release (beta, rc, etc.)
|
95
|
-
1. In the changelog,
|
95
|
+
1. In the changelog,
|
96
|
+
- Replace "Unreleased" with the date in iso-8601 format
|
97
|
+
- Add a new "Unreleased" section
|
96
98
|
1. In the readme,
|
97
|
-
-
|
98
|
-
-
|
99
|
+
- Update any other references to version number, including
|
100
|
+
- Update version number(s) in the documentation links table
|
99
101
|
1. Commit
|
100
|
-
1.
|
101
|
-
1.
|
102
|
-
1.
|
103
|
-
1.
|
102
|
+
1. git tag -a -m "v5.0.0" "v5.0.0" # or whatever number
|
103
|
+
1. git push --tags origin master
|
104
|
+
1. gem build paper_trail.gemspec
|
105
|
+
1. gem push paper_trail-5.0.0.gem
|
104
106
|
|
105
107
|
[1]: https://github.com/airblade/paper_trail/blob/master/doc/bug_report_template.rb
|
data/.rubocop.yml
CHANGED
@@ -17,10 +17,6 @@ Metrics/AbcSize:
|
|
17
17
|
Exclude:
|
18
18
|
- 'test/dummy/db/migrate/*'
|
19
19
|
|
20
|
-
Metrics/ClassLength:
|
21
|
-
Exclude:
|
22
|
-
- test/**/*
|
23
|
-
|
24
20
|
# The Ruby Style Guide recommends to "Limit lines to 80 characters."
|
25
21
|
# (https://github.com/bbatsov/ruby-style-guide#80-character-limits)
|
26
22
|
# but 100 is also reasonable.
|
data/.rubocop_todo.yml
CHANGED
@@ -4,11 +4,16 @@
|
|
4
4
|
Metrics/AbcSize:
|
5
5
|
Max: 30 # Goal: 15
|
6
6
|
|
7
|
+
Metrics/ClassLength:
|
8
|
+
Max: 400
|
9
|
+
Exclude:
|
10
|
+
- test/**/*
|
11
|
+
|
7
12
|
Metrics/CyclomaticComplexity:
|
8
13
|
Max: 13 # Goal: 6
|
9
14
|
|
10
15
|
Metrics/ModuleLength:
|
11
|
-
Max:
|
16
|
+
Max: 317
|
12
17
|
|
13
18
|
Metrics/PerceivedComplexity:
|
14
19
|
Max: 16 # Goal: 7
|
data/CHANGELOG.md
CHANGED
@@ -1,9 +1,33 @@
|
|
1
|
-
##
|
1
|
+
## ?.?.? (Unreleased)
|
2
2
|
|
3
3
|
### Breaking Changes
|
4
4
|
|
5
5
|
- None
|
6
6
|
|
7
|
+
### Deprecated
|
8
|
+
|
9
|
+
- None
|
10
|
+
|
11
|
+
### Added
|
12
|
+
|
13
|
+
- None
|
14
|
+
|
15
|
+
### Fixed
|
16
|
+
|
17
|
+
- None
|
18
|
+
|
19
|
+
## 5.2.0 (2016-06-27)
|
20
|
+
|
21
|
+
### Breaking Changes
|
22
|
+
|
23
|
+
- None
|
24
|
+
|
25
|
+
### Deprecated
|
26
|
+
|
27
|
+
- [#719](https://github.com/airblade/paper_trail/pull/719) -
|
28
|
+
The majority of model methods. Use paper_trail.x instead of x. Why? Your
|
29
|
+
models are a crowded namespace, and we want to get out of your way!
|
30
|
+
|
7
31
|
### Added
|
8
32
|
|
9
33
|
- None
|
@@ -122,6 +146,22 @@
|
|
122
146
|
- [#584](https://github.com/airblade/paper_trail/issues/584) -
|
123
147
|
Fixed deprecation warning for Active Record after_callback / after_commit
|
124
148
|
|
149
|
+
## 4.2.0 (2016-05-31)
|
150
|
+
|
151
|
+
### Breaking Changes
|
152
|
+
|
153
|
+
- None
|
154
|
+
|
155
|
+
### Added
|
156
|
+
|
157
|
+
- [#808](https://github.com/airblade/paper_trail/pull/808) -
|
158
|
+
Warn when destroy callback is set to :after with ActiveRecord 5
|
159
|
+
option `belongs_to_required_by_default` set to `true`.
|
160
|
+
|
161
|
+
### Fixed
|
162
|
+
|
163
|
+
- None
|
164
|
+
|
125
165
|
## 4.1.0 (2016-01-30)
|
126
166
|
|
127
167
|
### Breaking Changes
|
data/README.md
CHANGED
@@ -10,12 +10,12 @@ has been destroyed.
|
|
10
10
|
|
11
11
|
| Version | Documentation |
|
12
12
|
| -------------- | ------------- |
|
13
|
-
|
|
14
|
-
|
|
15
|
-
| 4.0
|
16
|
-
| 3
|
17
|
-
| 2
|
18
|
-
| 1
|
13
|
+
| Unreleased | https://github.com/airblade/paper_trail/blob/master/README.md |
|
14
|
+
| 5.2.0 | https://github.com/airblade/paper_trail/blob/v5.2.0/README.md |
|
15
|
+
| 4.2.0 | https://github.com/airblade/paper_trail/blob/v4.2.0/README.md |
|
16
|
+
| 3.0.9 | https://github.com/airblade/paper_trail/blob/v3.0.9/README.md |
|
17
|
+
| 2.7.2 | https://github.com/airblade/paper_trail/blob/v2.7.2/README.md |
|
18
|
+
| 1.6.5 | https://github.com/airblade/paper_trail/blob/v1.6.5/README.md |
|
19
19
|
|
20
20
|
## Table of Contents
|
21
21
|
|
@@ -56,7 +56,7 @@ has been destroyed.
|
|
56
56
|
| paper_trail | branch | tags | ruby | activerecord |
|
57
57
|
| -------------- | ---------- | ------ | -------- | ------------ |
|
58
58
|
| 5 | master | v5.x | >= 1.9.3 | >= 3.0, < 6 |
|
59
|
-
| 4 | 4
|
59
|
+
| 4 | 4-stable | v4.x | >= 1.8.7 | >= 3.0, < 6 |
|
60
60
|
| 3 | 3.0-stable | v3.x | >= 1.8.7 | >= 3.0, < 5 |
|
61
61
|
| 2 | 2.7-stable | v2.x | >= 1.8.7 | >= 3.0, < 4 |
|
62
62
|
| 1 | rails2 | v1.x | >= 1.8.7 | >= 2.3, < 3 |
|
@@ -171,35 +171,35 @@ widget.version
|
|
171
171
|
|
172
172
|
# Returns true if this widget is the current, live one; or false if it is from
|
173
173
|
# a previous version.
|
174
|
-
widget.live?
|
174
|
+
widget.paper_trail.live?
|
175
175
|
|
176
176
|
# Returns who put the widget into its current state.
|
177
|
-
widget.
|
177
|
+
widget.paper_trail.originator
|
178
178
|
|
179
179
|
# Returns the widget (not a version) as it looked at the given timestamp.
|
180
|
-
widget.version_at(timestamp)
|
180
|
+
widget.paper_trail.version_at(timestamp)
|
181
181
|
|
182
182
|
# Returns the widget (not a version) as it was most recently.
|
183
|
-
widget.previous_version
|
183
|
+
widget.paper_trail.previous_version
|
184
184
|
|
185
185
|
# Returns the widget (not a version) as it became next.
|
186
|
-
widget.next_version
|
186
|
+
widget.paper_trail.next_version
|
187
187
|
|
188
188
|
# Generates a version for a `touch` event (`widget.touch` does NOT generate a
|
189
189
|
# version)
|
190
|
-
widget.touch_with_version
|
190
|
+
widget.paper_trail.touch_with_version
|
191
191
|
|
192
192
|
# Turn PaperTrail off for all widgets.
|
193
|
-
Widget.
|
193
|
+
Widget.paper_trail.disable
|
194
194
|
|
195
195
|
# Turn PaperTrail on for all widgets.
|
196
|
-
Widget.
|
196
|
+
Widget.paper_trail.enable
|
197
197
|
|
198
198
|
# Is PaperTrail enabled for Widget, the class?
|
199
|
-
Widget.
|
199
|
+
Widget.paper_trail.enabled?
|
200
200
|
|
201
201
|
# Is PaperTrail enabled for widget, the instance?
|
202
|
-
widget.
|
202
|
+
widget.paper_trail.enabled_for_model?
|
203
203
|
```
|
204
204
|
|
205
205
|
And a `PaperTrail::Version` instance (which is just an ordinary ActiveRecord
|
@@ -302,13 +302,13 @@ class Article < ActiveRecord::Base
|
|
302
302
|
has_paper_trail :on => []
|
303
303
|
|
304
304
|
# Add callbacks in the order you need.
|
305
|
-
|
306
|
-
|
307
|
-
|
305
|
+
paper_trail.on_destroy # add destroy callback
|
306
|
+
paper_trail.on_update # etc.
|
307
|
+
paper_trail.on_create
|
308
308
|
end
|
309
309
|
```
|
310
310
|
|
311
|
-
The `
|
311
|
+
The `paper_trail.on_destroy` method can be further configured to happen
|
312
312
|
`:before` or `:after` the destroy event. In PaperTrail 4, the default is
|
313
313
|
`:after`. In PaperTrail 5, the default will be `:before`, to support
|
314
314
|
ActiveRecord 5. (see https://github.com/airblade/paper_trail/pull/683)
|
@@ -354,7 +354,7 @@ a.update_attributes :title => 'My Title', :rating => 3
|
|
354
354
|
a.versions.length # 1
|
355
355
|
a.update_attributes :title => 'Greeting', :content => 'Hello'
|
356
356
|
a.versions.length # 2
|
357
|
-
a.previous_version.title
|
357
|
+
a.paper_trail.previous_version.title # 'My Title'
|
358
358
|
```
|
359
359
|
|
360
360
|
Or, you can specify a list of all attributes you care about:
|
@@ -374,7 +374,7 @@ a.update_attributes :title => 'My Title'
|
|
374
374
|
a.versions.length # 2
|
375
375
|
a.update_attributes :content => 'Hello'
|
376
376
|
a.versions.length # 2
|
377
|
-
a.previous_version.content
|
377
|
+
a.paper_trail.previous_version.content # nil
|
378
378
|
```
|
379
379
|
|
380
380
|
The `:ignore` and `:only` options can also accept `Hash` arguments, where the :
|
@@ -397,10 +397,10 @@ a.update_attributes :title => 'My Title'
|
|
397
397
|
a.versions.length # 3
|
398
398
|
a.update_attributes :content => 'Hai'
|
399
399
|
a.versions.length # 3
|
400
|
-
a.previous_version.content
|
400
|
+
a.paper_trail.previous_version.content # "Hello"
|
401
401
|
a.update_attributes :title => 'Dif Title'
|
402
402
|
a.versions.length # 4
|
403
|
-
a.previous_version.content
|
403
|
+
a.paper_trail.previous_version.content # "Hai"
|
404
404
|
```
|
405
405
|
|
406
406
|
Passing both `:ignore` and `:only` options will result in the article being
|
@@ -455,8 +455,8 @@ end
|
|
455
455
|
#### Per Class
|
456
456
|
|
457
457
|
```ruby
|
458
|
-
Widget.
|
459
|
-
Widget.
|
458
|
+
Widget.paper_trail.disable
|
459
|
+
Widget.paper_trail.enable
|
460
460
|
```
|
461
461
|
|
462
462
|
#### Per Method
|
@@ -465,13 +465,13 @@ You can call a method without creating a new version using `without_versioning`.
|
|
465
465
|
It takes either a method name as a symbol:
|
466
466
|
|
467
467
|
```ruby
|
468
|
-
@widget.without_versioning :destroy
|
468
|
+
@widget.paper_trail.without_versioning :destroy
|
469
469
|
```
|
470
470
|
|
471
471
|
Or a block:
|
472
472
|
|
473
473
|
```ruby
|
474
|
-
@widget.without_versioning do
|
474
|
+
@widget.paper_trail.without_versioning do
|
475
475
|
@widget.update_attributes :name => 'Ford'
|
476
476
|
end
|
477
477
|
```
|
@@ -498,15 +498,15 @@ PaperTrail makes reverting to a previous version easy:
|
|
498
498
|
widget = Widget.find 42
|
499
499
|
widget.update_attributes :name => 'Blah blah'
|
500
500
|
# Time passes....
|
501
|
-
widget = widget.previous_version # the widget as it was before the update
|
502
|
-
widget.save
|
501
|
+
widget = widget.paper_trail.previous_version # the widget as it was before the update
|
502
|
+
widget.save # reverted
|
503
503
|
```
|
504
504
|
|
505
505
|
Alternatively you can find the version at a given time:
|
506
506
|
|
507
507
|
```ruby
|
508
|
-
widget = widget.version_at(1.day.ago) # the widget as it was one day ago
|
509
|
-
widget.save
|
508
|
+
widget = widget.paper_trail.version_at(1.day.ago) # the widget as it was one day ago
|
509
|
+
widget.save # reverted
|
510
510
|
```
|
511
511
|
|
512
512
|
Note `version_at` gives you the object, not a version, so you don't need to call
|
@@ -519,7 +519,7 @@ widget = Widget.find 42
|
|
519
519
|
widget.destroy
|
520
520
|
# Time passes....
|
521
521
|
widget = PaperTrail::Version.find(153).reify # the widget as it was before destruction
|
522
|
-
widget.save
|
522
|
+
widget.save # the widget lives!
|
523
523
|
```
|
524
524
|
|
525
525
|
You could even use PaperTrail to implement an undo system, [Ryan Bates has!][3]
|
@@ -534,11 +534,11 @@ was/became. Note that these methods reify the item for you.
|
|
534
534
|
|
535
535
|
```ruby
|
536
536
|
live_widget = Widget.find 42
|
537
|
-
live_widget.versions.length
|
538
|
-
widget = live_widget.previous_version # => widget == live_widget.versions.last.reify
|
539
|
-
widget = widget.previous_version # => widget == live_widget.versions[-2].reify
|
540
|
-
widget = widget.next_version # => widget == live_widget.versions.last.reify
|
541
|
-
widget.next_version # live_widget
|
537
|
+
live_widget.versions.length # 4, for example
|
538
|
+
widget = live_widget.paper_trail.previous_version # => widget == live_widget.versions.last.reify
|
539
|
+
widget = widget.paper_trail.previous_version # => widget == live_widget.versions[-2].reify
|
540
|
+
widget = widget.paper_trail.next_version # => widget == live_widget.versions.last.reify
|
541
|
+
widget.paper_trail.next_version # live_widget
|
542
542
|
```
|
543
543
|
|
544
544
|
If instead you have a particular `version` of an item you can navigate to the
|
@@ -572,7 +572,7 @@ it came instead from a previous version -- with `live?`:
|
|
572
572
|
```ruby
|
573
573
|
widget = Widget.find 42
|
574
574
|
widget.live? # true
|
575
|
-
widget = widget.previous_version
|
575
|
+
widget = widget.paper_trail.previous_version
|
576
576
|
widget.live? # false
|
577
577
|
```
|
578
578
|
|
@@ -729,10 +729,10 @@ like it does, call `paper_trail_originator` on the object.
|
|
729
729
|
widget = Widget.find 153 # assume widget has 0 versions
|
730
730
|
PaperTrail.whodunnit = 'Alice'
|
731
731
|
widget.update_attributes :name => 'Yankee'
|
732
|
-
widget.
|
732
|
+
widget.paper_trail.originator # 'Alice'
|
733
733
|
PaperTrail.whodunnit = 'Bob'
|
734
734
|
widget.update_attributes :name => 'Zulu'
|
735
|
-
widget.
|
735
|
+
widget.paper_trail.originator # 'Bob'
|
736
736
|
first_version, last_version = widget.versions.first, widget.versions.last
|
737
737
|
first_version.whodunnit # 'Alice'
|
738
738
|
first_version.paper_trail_originator # nil
|
@@ -1069,7 +1069,9 @@ class Post < ActiveRecord::Base
|
|
1069
1069
|
end
|
1070
1070
|
```
|
1071
1071
|
|
1072
|
-
Unlike ActiveRecord's `class_name`, you'll have to supply the complete module
|
1072
|
+
Unlike ActiveRecord's `class_name`, you'll have to supply the complete module
|
1073
|
+
path to the class (e.g. `Foo::BarVersion` if your class is inside the module
|
1074
|
+
`Foo`).
|
1073
1075
|
|
1074
1076
|
#### Advantages
|
1075
1077
|
|
data/lib/paper_trail.rb
CHANGED
@@ -90,11 +90,16 @@ module PaperTrail
|
|
90
90
|
end
|
91
91
|
|
92
92
|
def warn_about_not_setting_whodunnit
|
93
|
-
|
93
|
+
return unless ::PaperTrail.enabled_for_controller?
|
94
|
+
|
94
95
|
user_present = user_for_paper_trail.present?
|
95
96
|
whodunnit_blank = ::PaperTrail.whodunnit.blank?
|
96
|
-
if
|
97
|
+
if user_present && whodunnit_blank && !@set_paper_trail_whodunnit_called
|
98
|
+
source_file_location = self.class.instance_methods(false).map { |m|
|
99
|
+
self.class.instance_method(m).source_location.first
|
100
|
+
}.uniq.first
|
97
101
|
::Kernel.warn <<-EOS.strip_heredoc
|
102
|
+
#{source_file_location}:
|
98
103
|
user_for_paper_trail is present, but whodunnit has not been set.
|
99
104
|
PaperTrail no longer adds the set_paper_trail_whodunnit callback for
|
100
105
|
you. To continue recording whodunnit, please add this before_action
|
@@ -2,13 +2,17 @@ require "active_support/core_ext/object" # provides the `try` method
|
|
2
2
|
require "paper_trail/attribute_serializers/legacy_active_record_shim"
|
3
3
|
require "paper_trail/attribute_serializers/object_attribute"
|
4
4
|
require "paper_trail/attribute_serializers/object_changes_attribute"
|
5
|
+
require "paper_trail/model_config"
|
6
|
+
require "paper_trail/record_trail"
|
5
7
|
|
6
8
|
module PaperTrail
|
7
9
|
# Extensions to `ActiveRecord::Base`. See `frameworks/active_record.rb`.
|
10
|
+
# It is our goal to have the smallest possible footprint here, because
|
11
|
+
# `ActiveRecord::Base` is a very crowded namespace! That is why we introduced
|
12
|
+
# `.paper_trail` and `#paper_trail`.
|
8
13
|
module Model
|
9
14
|
def self.included(base)
|
10
15
|
base.send :extend, ClassMethods
|
11
|
-
base.send :attr_accessor, :paper_trail_habtm
|
12
16
|
end
|
13
17
|
|
14
18
|
# :nodoc:
|
@@ -58,615 +62,312 @@ module PaperTrail
|
|
58
62
|
#
|
59
63
|
# @api public
|
60
64
|
def has_paper_trail(options = {})
|
61
|
-
options
|
62
|
-
|
63
|
-
# Wrap the :on option in an array if necessary. This allows a single
|
64
|
-
# symbol to be passed in.
|
65
|
-
options[:on] = Array(options[:on])
|
66
|
-
|
67
|
-
setup_model_for_paper_trail(options)
|
68
|
-
|
69
|
-
setup_callbacks_from_options options[:on]
|
70
|
-
|
71
|
-
setup_callbacks_for_habtm options[:join_tables]
|
72
|
-
end
|
73
|
-
|
74
|
-
def update_for_callback(name, callback, model, assoc)
|
75
|
-
model.paper_trail_habtm ||= {}
|
76
|
-
model.paper_trail_habtm.reverse_merge!(name => { removed: [], added: [] })
|
77
|
-
case callback
|
78
|
-
when :before_add
|
79
|
-
model.paper_trail_habtm[name][:added] |= [assoc.id]
|
80
|
-
model.paper_trail_habtm[name][:removed] -= [assoc.id]
|
81
|
-
when :before_remove
|
82
|
-
model.paper_trail_habtm[name][:removed] |= [assoc.id]
|
83
|
-
model.paper_trail_habtm[name][:added] -= [assoc.id]
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
attr_reader :paper_trail_save_join_tables
|
88
|
-
|
89
|
-
def setup_callbacks_for_habtm(join_tables)
|
90
|
-
@paper_trail_save_join_tables = Array.wrap(join_tables)
|
91
|
-
# Adds callbacks to record changes to habtm associations such that on
|
92
|
-
# save the previous version of the association (if changed) can be
|
93
|
-
# interpreted
|
94
|
-
reflect_on_all_associations(:has_and_belongs_to_many).
|
95
|
-
reject { |a| paper_trail_options[:skip].include?(a.name.to_s) }.
|
96
|
-
each do |a|
|
97
|
-
added_callback = lambda do |*args|
|
98
|
-
update_for_callback(a.name, :before_add, args[-2], args.last)
|
99
|
-
end
|
100
|
-
removed_callback = lambda do |*args|
|
101
|
-
update_for_callback(a.name, :before_remove, args[-2], args.last)
|
102
|
-
end
|
103
|
-
send(:"before_add_for_#{a.name}").send(:<<, added_callback)
|
104
|
-
send(:"before_remove_for_#{a.name}").send(:<<, removed_callback)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
# Installs callbacks, associations, "class attributes", and more.
|
109
|
-
# For details of how "class attributes" work, see the activesupport docs.
|
110
|
-
# @api private
|
111
|
-
def setup_model_for_paper_trail(options = {})
|
112
|
-
# Lazily include the instance methods so we don't clutter up
|
113
|
-
# any more ActiveRecord models than we have to.
|
114
|
-
send :include, InstanceMethods
|
115
|
-
|
116
|
-
if ::ActiveRecord::VERSION::STRING < "4.2"
|
117
|
-
send :extend, AttributeSerializers::LegacyActiveRecordShim
|
118
|
-
end
|
119
|
-
|
120
|
-
class_attribute :version_association_name
|
121
|
-
self.version_association_name = options[:version] || :version
|
122
|
-
|
123
|
-
# The version this instance was reified from.
|
124
|
-
attr_accessor version_association_name
|
125
|
-
|
126
|
-
class_attribute :version_class_name
|
127
|
-
self.version_class_name = options[:class_name] || "PaperTrail::Version"
|
128
|
-
|
129
|
-
setup_paper_trail_options(options)
|
130
|
-
|
131
|
-
class_attribute :versions_association_name
|
132
|
-
self.versions_association_name = options[:versions] || :versions
|
65
|
+
paper_trail.setup(options)
|
66
|
+
end
|
133
67
|
|
134
|
-
|
68
|
+
# @api public
|
69
|
+
def paper_trail
|
70
|
+
::PaperTrail::ModelConfig.new(self)
|
71
|
+
end
|
135
72
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
has_many versions_association_name,
|
143
|
-
class_name: version_class_name,
|
144
|
-
as: :item,
|
145
|
-
order: paper_trail_version_class.timestamp_sort_order
|
146
|
-
end
|
73
|
+
# @api private
|
74
|
+
def paper_trail_deprecate(new_method, old_method = nil)
|
75
|
+
old = old_method.nil? ? new_method : old_method
|
76
|
+
msg = format("Use paper_trail.%s instead of %s", new_method, old)
|
77
|
+
::ActiveSupport::Deprecation.warn(msg, caller(2))
|
78
|
+
end
|
147
79
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
80
|
+
# @deprecated
|
81
|
+
def paper_trail_on_destroy(*args)
|
82
|
+
paper_trail_deprecate "on_destroy", "paper_trail_on_destroy"
|
83
|
+
paper_trail.on_destroy(*args)
|
152
84
|
end
|
153
85
|
|
154
|
-
#
|
155
|
-
# @api private
|
156
|
-
def setup_paper_trail_options(options)
|
157
|
-
class_attribute :paper_trail_options
|
158
|
-
self.paper_trail_options = options.dup
|
159
|
-
[:ignore, :skip, :only].each do |k|
|
160
|
-
paper_trail_options[k] = [paper_trail_options[k]].flatten.compact.map { |attr|
|
161
|
-
attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s
|
162
|
-
}
|
163
|
-
end
|
164
|
-
paper_trail_options[:meta] ||= {}
|
165
|
-
if paper_trail_options[:save_changes].nil?
|
166
|
-
paper_trail_options[:save_changes] = true
|
167
|
-
end
|
168
|
-
end
|
169
|
-
|
170
|
-
def setup_callbacks_from_options(options_on = [])
|
171
|
-
options_on.each do |option|
|
172
|
-
send "paper_trail_on_#{option}"
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
# Record version before or after "destroy" event
|
177
|
-
def paper_trail_on_destroy(recording_order = "before")
|
178
|
-
unless %w(after before).include?(recording_order.to_s)
|
179
|
-
raise ArgumentError, 'recording order can only be "after" or "before"'
|
180
|
-
end
|
181
|
-
|
182
|
-
if recording_order.to_s == "after" &&
|
183
|
-
Gem::Version.new(ActiveRecord::VERSION::STRING).release >= Gem::Version.new("5")
|
184
|
-
if ::ActiveRecord::Base.belongs_to_required_by_default
|
185
|
-
::ActiveSupport::Deprecation.warn(
|
186
|
-
"paper_trail_on_destroy(:after) is incompatible with ActiveRecord " +
|
187
|
-
"belongs_to_required_by_default and has no effect. Please use :before " +
|
188
|
-
"or disable belongs_to_required_by_default."
|
189
|
-
)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
|
-
send "#{recording_order}_destroy", :record_destroy, if: :save_version?
|
194
|
-
|
195
|
-
return if paper_trail_options[:on].include?(:destroy)
|
196
|
-
paper_trail_options[:on] << :destroy
|
197
|
-
end
|
198
|
-
|
199
|
-
# Record version after "update" event
|
86
|
+
# @deprecated
|
200
87
|
def paper_trail_on_update
|
201
|
-
|
202
|
-
|
203
|
-
after_update :clear_version_instance!
|
204
|
-
|
205
|
-
return if paper_trail_options[:on].include?(:update)
|
206
|
-
paper_trail_options[:on] << :update
|
88
|
+
paper_trail_deprecate "on_update", "paper_trail_on_update"
|
89
|
+
paper_trail.on_update
|
207
90
|
end
|
208
91
|
|
209
|
-
#
|
92
|
+
# @deprecated
|
210
93
|
def paper_trail_on_create
|
211
|
-
|
212
|
-
|
213
|
-
return if paper_trail_options[:on].include?(:create)
|
214
|
-
paper_trail_options[:on] << :create
|
94
|
+
paper_trail_deprecate "on_create", "paper_trail_on_create"
|
95
|
+
paper_trail.on_create
|
215
96
|
end
|
216
97
|
|
217
|
-
#
|
98
|
+
# @deprecated
|
218
99
|
def paper_trail_off!
|
219
|
-
|
100
|
+
paper_trail_deprecate "disable", "paper_trail_off!"
|
101
|
+
paper_trail.disable
|
220
102
|
end
|
221
103
|
|
222
|
-
#
|
104
|
+
# @deprecated
|
223
105
|
def paper_trail_on!
|
224
|
-
|
106
|
+
paper_trail_deprecate "enable", "paper_trail_on!"
|
107
|
+
paper_trail.enable
|
225
108
|
end
|
226
109
|
|
110
|
+
# @deprecated
|
227
111
|
def paper_trail_enabled_for_model?
|
228
|
-
|
229
|
-
|
112
|
+
paper_trail_deprecate "enabled?", "paper_trail_enabled_for_model?"
|
113
|
+
paper_trail.enabled?
|
230
114
|
end
|
231
115
|
|
116
|
+
# @deprecated
|
232
117
|
def paper_trail_version_class
|
233
|
-
|
118
|
+
paper_trail_deprecate "version_class", "paper_trail_version_class"
|
119
|
+
paper_trail.version_class
|
234
120
|
end
|
235
121
|
end
|
236
122
|
|
237
123
|
# Wrap the following methods in a module so we can include them only in the
|
238
124
|
# ActiveRecord models that declare `has_paper_trail`.
|
239
125
|
module InstanceMethods
|
240
|
-
|
241
|
-
|
126
|
+
def paper_trail
|
127
|
+
::PaperTrail::RecordTrail.new(self)
|
128
|
+
end
|
129
|
+
|
130
|
+
# @deprecated
|
242
131
|
def live?
|
243
|
-
|
132
|
+
self.class.paper_trail_deprecate "live?"
|
133
|
+
paper_trail.live?
|
244
134
|
end
|
245
135
|
|
246
|
-
#
|
136
|
+
# @deprecated
|
247
137
|
def paper_trail_originator
|
248
|
-
|
138
|
+
self.class.paper_trail_deprecate "originator", "paper_trail_originator"
|
139
|
+
paper_trail.originator
|
249
140
|
end
|
250
141
|
|
142
|
+
# @deprecated
|
251
143
|
def originator
|
252
|
-
|
253
|
-
|
144
|
+
self.class.paper_trail_deprecate "originator"
|
145
|
+
paper_trail.originator
|
254
146
|
end
|
255
147
|
|
256
|
-
#
|
257
|
-
# for changes that never actually took place.
|
258
|
-
# Optimization: Use lazy `reset` instead of eager `reload` because, in
|
259
|
-
# many use cases, the association will not be used.
|
148
|
+
# @deprecated
|
260
149
|
def clear_rolled_back_versions
|
261
|
-
|
150
|
+
self.class.paper_trail_deprecate "clear_rolled_back_versions"
|
151
|
+
paper_trail.clear_rolled_back_versions
|
262
152
|
end
|
263
153
|
|
264
|
-
#
|
265
|
-
def
|
266
|
-
|
267
|
-
|
268
|
-
v = send(self.class.versions_association_name).subsequent(timestamp, true).first
|
269
|
-
return v.reify(reify_options) if v
|
270
|
-
self unless destroyed?
|
154
|
+
# @deprecated
|
155
|
+
def source_version
|
156
|
+
self.class.paper_trail_deprecate "source_version"
|
157
|
+
paper_trail.source_version
|
271
158
|
end
|
272
159
|
|
273
|
-
#
|
274
|
-
|
275
|
-
|
160
|
+
# @deprecated
|
161
|
+
def version_at(*args)
|
162
|
+
self.class.paper_trail_deprecate "version_at"
|
163
|
+
paper_trail.version_at(*args)
|
164
|
+
end
|
165
|
+
|
166
|
+
# @deprecated
|
276
167
|
def versions_between(start_time, end_time, _reify_options = {})
|
277
|
-
|
278
|
-
|
168
|
+
self.class.paper_trail_deprecate "versions_between"
|
169
|
+
paper_trail.versions_between(start_time, end_time)
|
279
170
|
end
|
280
171
|
|
281
|
-
#
|
172
|
+
# @deprecated
|
282
173
|
def previous_version
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
end
|
289
|
-
previous.try(:reify)
|
290
|
-
end
|
291
|
-
|
292
|
-
# Returns the object (not a Version) as it became next.
|
293
|
-
# NOTE: if self (the item) was not reified from a version, i.e. it is the
|
294
|
-
# "live" item, we return nil. Perhaps we should return self instead?
|
174
|
+
self.class.paper_trail_deprecate "previous_version"
|
175
|
+
paper_trail.previous_version
|
176
|
+
end
|
177
|
+
|
178
|
+
# @deprecated
|
295
179
|
def next_version
|
296
|
-
|
297
|
-
|
298
|
-
rescue
|
299
|
-
nil
|
180
|
+
self.class.paper_trail_deprecate "next_version"
|
181
|
+
paper_trail.next_version
|
300
182
|
end
|
301
183
|
|
184
|
+
# @deprecated
|
302
185
|
def paper_trail_enabled_for_model?
|
303
|
-
self.class.paper_trail_enabled_for_model?
|
304
|
-
|
305
|
-
|
306
|
-
# Executes the given method or block without creating a new version.
|
307
|
-
def without_versioning(method = nil)
|
308
|
-
paper_trail_was_enabled = paper_trail_enabled_for_model?
|
309
|
-
self.class.paper_trail_off!
|
310
|
-
method ? method.to_proc.call(self) : yield(self)
|
311
|
-
ensure
|
312
|
-
self.class.paper_trail_on! if paper_trail_was_enabled
|
313
|
-
end
|
314
|
-
|
315
|
-
# Utility method for reifying. Anything executed inside the block will
|
316
|
-
# appear like a new record.
|
317
|
-
def appear_as_new_record
|
318
|
-
instance_eval {
|
319
|
-
alias :old_new_record? :new_record?
|
320
|
-
alias :new_record? :present?
|
321
|
-
}
|
322
|
-
yield
|
323
|
-
instance_eval { alias :new_record? :old_new_record? }
|
324
|
-
end
|
325
|
-
|
326
|
-
# Temporarily overwrites the value of whodunnit and then executes the
|
327
|
-
# provided block.
|
328
|
-
def whodunnit(value)
|
329
|
-
raise ArgumentError, "expected to receive a block" unless block_given?
|
330
|
-
current_whodunnit = PaperTrail.whodunnit
|
331
|
-
PaperTrail.whodunnit = value
|
332
|
-
yield self
|
333
|
-
ensure
|
334
|
-
PaperTrail.whodunnit = current_whodunnit
|
335
|
-
end
|
336
|
-
|
337
|
-
# Mimics the `touch` method from `ActiveRecord::Persistence`, but also
|
338
|
-
# creates a version. A version is created regardless of options such as
|
339
|
-
# `:on`, `:if`, or `:unless`.
|
340
|
-
#
|
341
|
-
# TODO: look into leveraging the `after_touch` callback from
|
342
|
-
# `ActiveRecord` to allow the regular `touch` method to generate a version
|
343
|
-
# as normal. May make sense to switch the `record_update` method to
|
344
|
-
# leverage an `after_update` callback anyways (likely for v4.0.0)
|
345
|
-
def touch_with_version(name = nil)
|
346
|
-
raise ActiveRecordError, "can not touch on a new record object" unless persisted?
|
347
|
-
|
348
|
-
attributes = timestamp_attributes_for_update_in_model
|
349
|
-
attributes << name if name
|
350
|
-
current_time = current_time_from_proper_timezone
|
351
|
-
|
352
|
-
attributes.each { |column| write_attribute(column, current_time) }
|
186
|
+
self.class.paper_trail_deprecate "enabled_for_model?", "paper_trail_enabled_for_model?"
|
187
|
+
paper_trail.enabled_for_model?
|
188
|
+
end
|
353
189
|
|
354
|
-
|
355
|
-
|
190
|
+
# @deprecated
|
191
|
+
def without_versioning(method = nil, &block)
|
192
|
+
self.class.paper_trail_deprecate "without_versioning"
|
193
|
+
paper_trail.without_versioning(method, &block)
|
356
194
|
end
|
357
195
|
|
358
|
-
|
196
|
+
# @deprecated
|
197
|
+
def appear_as_new_record(&block)
|
198
|
+
self.class.paper_trail_deprecate "appear_as_new_record"
|
199
|
+
paper_trail.appear_as_new_record(&block)
|
200
|
+
end
|
359
201
|
|
360
|
-
#
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
on.nil? || on.include?(:update)
|
202
|
+
# @deprecated
|
203
|
+
def whodunnit(value, &block)
|
204
|
+
self.class.paper_trail_deprecate "whodunnit"
|
205
|
+
paper_trail.whodunnit(value, &block)
|
365
206
|
end
|
366
207
|
|
367
|
-
|
368
|
-
|
208
|
+
# @deprecated
|
209
|
+
def touch_with_version(name = nil)
|
210
|
+
self.class.paper_trail_deprecate "touch_with_version"
|
211
|
+
paper_trail.touch_with_version(name)
|
369
212
|
end
|
370
213
|
|
214
|
+
# `record_create` is deprecated in favor of `paper_trail.record_create`,
|
215
|
+
# but does not yet print a deprecation warning. When the `after_create`
|
216
|
+
# callback is registered (by ModelConfig#on_create) we still refer to this
|
217
|
+
# method by name, e.g.
|
218
|
+
#
|
219
|
+
# @model_class.after_create :record_create, if: :save_version?
|
220
|
+
#
|
221
|
+
# instead of using the preferred method `paper_trail.record_create`, e.g.
|
222
|
+
#
|
223
|
+
# @model_class.after_create { |r| r.paper_trail.record_create if r.save_version?}
|
224
|
+
#
|
225
|
+
# We still register the callback by name so that, if someone calls
|
226
|
+
# `has_paper_trail` twice, the callback will *not* be registered twice.
|
227
|
+
# Our own test suite calls `has_paper_trail` many times for the same
|
228
|
+
# class.
|
229
|
+
#
|
230
|
+
# In the future, perhaps we should require that users only set up
|
231
|
+
# PT once per class.
|
232
|
+
#
|
233
|
+
# @deprecated
|
371
234
|
def record_create
|
372
|
-
|
373
|
-
data = {
|
374
|
-
event: paper_trail_event || "create",
|
375
|
-
whodunnit: PaperTrail.whodunnit
|
376
|
-
}
|
377
|
-
if respond_to?(:updated_at)
|
378
|
-
data[PaperTrail.timestamp_field] = updated_at
|
379
|
-
end
|
380
|
-
if pt_record_object_changes? && changed_notably?
|
381
|
-
data[:object_changes] = pt_recordable_object_changes
|
382
|
-
end
|
383
|
-
add_transaction_id_to(data)
|
384
|
-
version = send(self.class.versions_association_name).create! merge_metadata(data)
|
385
|
-
update_transaction_id(version)
|
386
|
-
save_associations(version)
|
387
|
-
end
|
235
|
+
paper_trail.record_create
|
388
236
|
end
|
389
237
|
|
238
|
+
# See deprecation comment for `record_create`
|
239
|
+
# @deprecated
|
390
240
|
def record_update(force = nil)
|
391
|
-
|
392
|
-
|
393
|
-
|
394
|
-
|
395
|
-
whodunnit: PaperTrail.whodunnit
|
396
|
-
}
|
397
|
-
if respond_to?(:updated_at)
|
398
|
-
data[PaperTrail.timestamp_field] = updated_at
|
399
|
-
end
|
400
|
-
if pt_record_object_changes?
|
401
|
-
data[:object_changes] = pt_recordable_object_changes
|
402
|
-
end
|
403
|
-
add_transaction_id_to(data)
|
404
|
-
version = send(self.class.versions_association_name).create merge_metadata(data)
|
405
|
-
if version.errors.any?
|
406
|
-
log_version_errors(version, :update)
|
407
|
-
else
|
408
|
-
update_transaction_id(version)
|
409
|
-
save_associations(version)
|
410
|
-
end
|
411
|
-
end
|
412
|
-
end
|
413
|
-
|
414
|
-
# Returns a boolean indicating whether to store serialized version diffs
|
415
|
-
# in the `object_changes` column of the version record.
|
416
|
-
# @api private
|
241
|
+
paper_trail.record_update(force)
|
242
|
+
end
|
243
|
+
|
244
|
+
# @deprecated
|
417
245
|
def pt_record_object_changes?
|
418
|
-
|
419
|
-
|
246
|
+
self.class.paper_trail_deprecate "record_object_changes?", "pt_record_object_changes?"
|
247
|
+
paper_trail.record_object_changes?
|
420
248
|
end
|
421
249
|
|
422
|
-
#
|
423
|
-
# nascent version record. If the `object` column is a postgres `json`
|
424
|
-
# column, then a hash can be used in the assignment, otherwise the column
|
425
|
-
# is a `text` column, and we must perform the serialization here, using
|
426
|
-
# `PaperTrail.serializer`.
|
427
|
-
# @api private
|
250
|
+
# @deprecated
|
428
251
|
def pt_recordable_object
|
429
|
-
|
430
|
-
|
431
|
-
|
432
|
-
|
433
|
-
|
434
|
-
end
|
435
|
-
|
436
|
-
# Returns an object which can be assigned to the `object_changes`
|
437
|
-
# attribute of a nascent version record. If the `object_changes` column is
|
438
|
-
# a postgres `json` column, then a hash can be used in the assignment,
|
439
|
-
# otherwise the column is a `text` column, and we must perform the
|
440
|
-
# serialization here, using `PaperTrail.serializer`.
|
441
|
-
# @api private
|
252
|
+
self.class.paper_trail_deprecate "recordable_object", "pt_recordable_object"
|
253
|
+
paper_trail.recordable_object
|
254
|
+
end
|
255
|
+
|
256
|
+
# @deprecated
|
442
257
|
def pt_recordable_object_changes
|
443
|
-
|
444
|
-
|
445
|
-
else
|
446
|
-
PaperTrail.serializer.dump(changes_for_paper_trail)
|
447
|
-
end
|
258
|
+
self.class.paper_trail_deprecate "recordable_object_changes", "pt_recordable_object_changes"
|
259
|
+
paper_trail.recordable_object_changes
|
448
260
|
end
|
449
261
|
|
262
|
+
# @deprecated
|
450
263
|
def changes_for_paper_trail
|
451
|
-
|
452
|
-
|
453
|
-
new(self.class).
|
454
|
-
serialize(notable_changes)
|
455
|
-
notable_changes.to_hash
|
264
|
+
self.class.paper_trail_deprecate "changes", "changes_for_paper_trail"
|
265
|
+
paper_trail.changes
|
456
266
|
end
|
457
267
|
|
458
|
-
#
|
459
|
-
#
|
268
|
+
# See deprecation comment for `record_create`
|
269
|
+
# @deprecated
|
460
270
|
def clear_version_instance!
|
461
|
-
|
271
|
+
paper_trail.clear_version_instance
|
462
272
|
end
|
463
273
|
|
464
|
-
#
|
465
|
-
#
|
274
|
+
# See deprecation comment for `record_create`
|
275
|
+
# @deprecated
|
466
276
|
def reset_timestamp_attrs_for_update_if_needed!
|
467
|
-
|
468
|
-
timestamp_attributes_for_update_in_model.each do |column|
|
469
|
-
# ActiveRecord 4.2 deprecated `reset_column!` in favor of
|
470
|
-
# `restore_column!`.
|
471
|
-
if respond_to?("restore_#{column}!")
|
472
|
-
send("restore_#{column}!")
|
473
|
-
else
|
474
|
-
send("reset_#{column}!")
|
475
|
-
end
|
476
|
-
end
|
277
|
+
paper_trail.reset_timestamp_attrs_for_update_if_needed
|
477
278
|
end
|
478
279
|
|
280
|
+
# See deprecation comment for `record_create`
|
281
|
+
# @deprecated
|
479
282
|
def record_destroy
|
480
|
-
|
481
|
-
|
482
|
-
|
483
|
-
|
484
|
-
event: paper_trail_event || "destroy",
|
485
|
-
object: pt_recordable_object,
|
486
|
-
whodunnit: PaperTrail.whodunnit
|
487
|
-
}
|
488
|
-
add_transaction_id_to(data)
|
489
|
-
version = self.class.paper_trail_version_class.create(merge_metadata(data))
|
490
|
-
if version.errors.any?
|
491
|
-
log_version_errors(version, :destroy)
|
492
|
-
else
|
493
|
-
send("#{self.class.version_association_name}=", version)
|
494
|
-
send(self.class.versions_association_name).reset
|
495
|
-
update_transaction_id(version)
|
496
|
-
save_associations(version)
|
497
|
-
end
|
498
|
-
end
|
499
|
-
end
|
500
|
-
|
501
|
-
# Saves associations if the join table for `VersionAssociation` exists.
|
283
|
+
paper_trail.record_destroy
|
284
|
+
end
|
285
|
+
|
286
|
+
# @deprecated
|
502
287
|
def save_associations(version)
|
503
|
-
|
504
|
-
|
505
|
-
save_associations_has_and_belongs_to_many(version)
|
288
|
+
self.class.paper_trail_deprecate "save_associations"
|
289
|
+
paper_trail.save_associations(version)
|
506
290
|
end
|
507
291
|
|
292
|
+
# @deprecated
|
508
293
|
def save_associations_belongs_to(version)
|
509
|
-
self.class.
|
510
|
-
|
511
|
-
version_id: version.id,
|
512
|
-
foreign_key_name: assoc.foreign_key
|
513
|
-
}
|
514
|
-
|
515
|
-
if assoc.options[:polymorphic]
|
516
|
-
associated_record = send(assoc.name) if send(assoc.foreign_type)
|
517
|
-
if associated_record && associated_record.class.paper_trail_enabled_for_model?
|
518
|
-
assoc_version_args[:foreign_key_id] = associated_record.id
|
519
|
-
end
|
520
|
-
elsif assoc.klass.paper_trail_enabled_for_model?
|
521
|
-
assoc_version_args[:foreign_key_id] = send(assoc.foreign_key)
|
522
|
-
end
|
523
|
-
|
524
|
-
if assoc_version_args.key?(:foreign_key_id)
|
525
|
-
PaperTrail::VersionAssociation.create(assoc_version_args)
|
526
|
-
end
|
527
|
-
end
|
294
|
+
self.class.paper_trail_deprecate "save_associations_belongs_to"
|
295
|
+
paper_trail.save_associations_belongs_to(version)
|
528
296
|
end
|
529
297
|
|
298
|
+
# @deprecated
|
530
299
|
def save_associations_has_and_belongs_to_many(version)
|
531
|
-
|
532
|
-
|
533
|
-
|
534
|
-
|
535
|
-
|
536
|
-
a.klass.paper_trail_enabled_for_model?
|
537
|
-
assoc_version_args = {
|
538
|
-
version_id: version.transaction_id,
|
539
|
-
foreign_key_name: a.name
|
540
|
-
}
|
541
|
-
assoc_ids =
|
542
|
-
send(a.name).to_a.map(&:id) +
|
543
|
-
(@paper_trail_habtm.try(:[], a.name).try(:[], :removed) || []) -
|
544
|
-
(@paper_trail_habtm.try(:[], a.name).try(:[], :added) || [])
|
545
|
-
assoc_ids.each do |id|
|
546
|
-
PaperTrail::VersionAssociation.create(assoc_version_args.merge(foreign_key_id: id))
|
547
|
-
end
|
548
|
-
end
|
300
|
+
self.class.paper_trail_deprecate(
|
301
|
+
"save_associations_habtm",
|
302
|
+
"save_associations_has_and_belongs_to_many"
|
303
|
+
)
|
304
|
+
paper_trail.save_associations_habtm(version)
|
549
305
|
end
|
550
306
|
|
307
|
+
# @deprecated
|
308
|
+
# @api private
|
551
309
|
def reset_transaction_id
|
552
|
-
|
310
|
+
::ActiveSupport::Deprecation.warn(
|
311
|
+
"reset_transaction_id is deprecated, use PaperTrail.clear_transaction_id"
|
312
|
+
)
|
313
|
+
PaperTrail.clear_transaction_id
|
553
314
|
end
|
554
315
|
|
316
|
+
# @deprecated
|
317
|
+
# @api private
|
555
318
|
def merge_metadata(data)
|
556
|
-
|
557
|
-
|
558
|
-
data[k] =
|
559
|
-
if v.respond_to?(:call)
|
560
|
-
v.call(self)
|
561
|
-
elsif v.is_a?(Symbol) && respond_to?(v, true)
|
562
|
-
# If it is an attribute that is changing in an existing object,
|
563
|
-
# be sure to grab the current version.
|
564
|
-
if has_attribute?(v) && send("#{v}_changed?".to_sym) && data[:event] != "create"
|
565
|
-
send("#{v}_was".to_sym)
|
566
|
-
else
|
567
|
-
send(v)
|
568
|
-
end
|
569
|
-
else
|
570
|
-
v
|
571
|
-
end
|
572
|
-
end
|
573
|
-
|
574
|
-
# Second we merge any extra data from the controller (if available).
|
575
|
-
data.merge(PaperTrail.controller_info || {})
|
319
|
+
self.class.paper_trail_deprecate "merge_metadata"
|
320
|
+
paper_trail.merge_metadata(data)
|
576
321
|
end
|
577
322
|
|
323
|
+
# @deprecated
|
578
324
|
def attributes_before_change
|
579
|
-
|
580
|
-
|
325
|
+
self.class.paper_trail_deprecate "attributes_before_change"
|
326
|
+
paper_trail.attributes_before_change
|
581
327
|
end
|
582
328
|
|
583
|
-
#
|
584
|
-
# ommitting attributes to be skipped.
|
329
|
+
# @deprecated
|
585
330
|
def object_attrs_for_paper_trail
|
586
|
-
|
587
|
-
|
588
|
-
attrs
|
331
|
+
self.class.paper_trail_deprecate "object_attrs_for_paper_trail"
|
332
|
+
paper_trail.object_attrs_for_paper_trail
|
589
333
|
end
|
590
334
|
|
591
|
-
#
|
592
|
-
# instance. A timestamp-only update (e.g. only `updated_at` changed) is
|
593
|
-
# considered notable unless an ignored attribute was also changed.
|
335
|
+
# @deprecated
|
594
336
|
def changed_notably?
|
595
|
-
|
596
|
-
|
597
|
-
(notably_changed - timestamps).any?
|
598
|
-
else
|
599
|
-
notably_changed.any?
|
600
|
-
end
|
337
|
+
self.class.paper_trail_deprecate "changed_notably?"
|
338
|
+
paper_trail.changed_notably?
|
601
339
|
end
|
602
340
|
|
603
|
-
#
|
604
|
-
# and/or the `:skip` option. Returns true if an ignored attribute has
|
605
|
-
# changed.
|
341
|
+
# @deprecated
|
606
342
|
def ignored_attr_has_changed?
|
607
|
-
|
608
|
-
|
343
|
+
self.class.paper_trail_deprecate "ignored_attr_has_changed?"
|
344
|
+
paper_trail.ignored_attr_has_changed?
|
609
345
|
end
|
610
346
|
|
347
|
+
# @deprecated
|
611
348
|
def notably_changed
|
612
|
-
|
613
|
-
|
614
|
-
# keys of the hash) should also get pushed into the collection.
|
615
|
-
only.delete_if do |obj|
|
616
|
-
obj.is_a?(Hash) &&
|
617
|
-
obj.each { |attr, condition|
|
618
|
-
only << attr if condition.respond_to?(:call) && condition.call(self)
|
619
|
-
}
|
620
|
-
end
|
621
|
-
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
349
|
+
self.class.paper_trail_deprecate "notably_changed"
|
350
|
+
paper_trail.notably_changed
|
622
351
|
end
|
623
352
|
|
353
|
+
# @deprecated
|
624
354
|
def changed_and_not_ignored
|
625
|
-
|
626
|
-
|
627
|
-
# keys of the hash) should also get pushed into the collection.
|
628
|
-
ignore.delete_if do |obj|
|
629
|
-
obj.is_a?(Hash) &&
|
630
|
-
obj.each { |attr, condition|
|
631
|
-
ignore << attr if condition.respond_to?(:call) && condition.call(self)
|
632
|
-
}
|
633
|
-
end
|
634
|
-
skip = paper_trail_options[:skip]
|
635
|
-
changed - ignore - skip
|
355
|
+
self.class.paper_trail_deprecate "changed_and_not_ignored"
|
356
|
+
paper_trail.changed_and_not_ignored
|
636
357
|
end
|
637
358
|
|
359
|
+
# The new method is named "enabled?" for consistency.
|
360
|
+
# @deprecated
|
638
361
|
def paper_trail_switched_on?
|
639
|
-
|
640
|
-
|
641
|
-
paper_trail_enabled_for_model?
|
642
|
-
end
|
643
|
-
|
644
|
-
def save_version?
|
645
|
-
if_condition = paper_trail_options[:if]
|
646
|
-
unless_condition = paper_trail_options[:unless]
|
647
|
-
(if_condition.blank? || if_condition.call(self)) && !unless_condition.try(:call, self)
|
648
|
-
end
|
649
|
-
|
650
|
-
def add_transaction_id_to(data)
|
651
|
-
return unless self.class.paper_trail_version_class.column_names.include?("transaction_id")
|
652
|
-
data[:transaction_id] = PaperTrail.transaction_id
|
362
|
+
self.class.paper_trail_deprecate "enabled?", "paper_trail_switched_on?"
|
363
|
+
paper_trail.enabled?
|
653
364
|
end
|
654
365
|
|
366
|
+
# @deprecated
|
655
367
|
# @api private
|
656
|
-
def
|
657
|
-
|
658
|
-
|
659
|
-
PaperTrail.transaction_id = version.id
|
660
|
-
version.transaction_id = version.id
|
661
|
-
version.save
|
662
|
-
end
|
663
|
-
end
|
664
|
-
|
665
|
-
def log_version_errors(version, action)
|
666
|
-
version.logger.warn(
|
667
|
-
"Unable to create version for #{action} of #{self.class.name}##{id}: " +
|
668
|
-
version.errors.full_messages.join(", ")
|
669
|
-
)
|
368
|
+
def save_version?
|
369
|
+
self.class.paper_trail_deprecate "save_version?"
|
370
|
+
paper_trail.save_version?
|
670
371
|
end
|
671
372
|
end
|
672
373
|
end
|