paper_trail 10.2.0 → 10.2.1
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 +5 -5
- data/lib/paper_trail/events/base.rb +54 -25
- data/lib/paper_trail/events/create.rb +1 -0
- data/lib/paper_trail/events/update.rb +1 -0
- data/lib/paper_trail/record_trail.rb +49 -17
- data/lib/paper_trail/serializers/yaml.rb +5 -0
- data/lib/paper_trail/version_number.rb +1 -1
- metadata +19 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 35e835ccf1aa917cfbe1202f639d73f7e70f4f35e4845706f6edb8ba713004b3
|
4
|
+
data.tar.gz: eafb8a0ed8ddfc6daeafbd7fb8197c225a2a962a1e32f42664802b72f386d510
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2c22225eb860afba59822dac469c24bd6aa3fd9712a521a93187ce0ce497a2c66a022c8cb6615d1cfc13fbfc8ac9df386cf4f038ac1ec7fd78cea9611d86f26e
|
7
|
+
data.tar.gz: efb345a2262034ee6ac5366bc1825bb710b79ed3b80e99567bfe873cc1aca7815e8f5136e066358d542ad52aa777274059c3334d5b6fb56c4fff24ecc4521b65
|
@@ -59,14 +59,29 @@ module PaperTrail
|
|
59
59
|
end
|
60
60
|
|
61
61
|
# @api private
|
62
|
-
def
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
62
|
+
def nonskipped_attributes_before_change(is_touch)
|
63
|
+
cache_changed_attributes do
|
64
|
+
record_attributes = @record.attributes.except(*@record.paper_trail_options[:skip])
|
65
|
+
|
66
|
+
record_attributes.each_key do |k|
|
67
|
+
if @record.class.column_names.include?(k)
|
68
|
+
record_attributes[k] = attribute_in_previous_version(k, is_touch)
|
69
|
+
end
|
68
70
|
end
|
69
|
-
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# Rails 5.1 changed the API of `ActiveRecord::Dirty`.
|
75
|
+
# @api private
|
76
|
+
def cache_changed_attributes
|
77
|
+
if RAILS_GTE_5_1
|
78
|
+
# Everything works fine as it is
|
79
|
+
yield
|
80
|
+
else
|
81
|
+
# Any particular call to `changed_attributes` produces the huge memory allocation.
|
82
|
+
# Lets use the generic AR workaround for that.
|
83
|
+
@record.send(:cache_changed_attributes) { yield }
|
84
|
+
end
|
70
85
|
end
|
71
86
|
|
72
87
|
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
@@ -108,7 +123,8 @@ module PaperTrail
|
|
108
123
|
|
109
124
|
# @api private
|
110
125
|
def changed_in_latest_version
|
111
|
-
|
126
|
+
# Memoized to reduce memory usage
|
127
|
+
@changed_in_latest_version ||= changes_in_latest_version.keys
|
112
128
|
end
|
113
129
|
|
114
130
|
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
@@ -116,10 +132,13 @@ module PaperTrail
|
|
116
132
|
#
|
117
133
|
# @api private
|
118
134
|
def changes_in_latest_version
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
135
|
+
# Memoized to reduce memory usage
|
136
|
+
@changes_in_latest_version ||= begin
|
137
|
+
if @in_after_callback && RAILS_GTE_5_1
|
138
|
+
@record.saved_changes
|
139
|
+
else
|
140
|
+
@record.changes
|
141
|
+
end
|
123
142
|
end
|
124
143
|
end
|
125
144
|
|
@@ -200,16 +219,19 @@ module PaperTrail
|
|
200
219
|
|
201
220
|
# @api private
|
202
221
|
def notably_changed
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
222
|
+
# Memoized to reduce memory usage
|
223
|
+
@notably_changed ||= begin
|
224
|
+
only = @record.paper_trail_options[:only].dup
|
225
|
+
# Remove Hash arguments and then evaluate whether the attributes (the
|
226
|
+
# keys of the hash) should also get pushed into the collection.
|
227
|
+
only.delete_if do |obj|
|
228
|
+
obj.is_a?(Hash) &&
|
229
|
+
obj.each { |attr, condition|
|
230
|
+
only << attr if condition.respond_to?(:call) && condition.call(@record)
|
231
|
+
}
|
232
|
+
end
|
233
|
+
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
211
234
|
end
|
212
|
-
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
213
235
|
end
|
214
236
|
|
215
237
|
# Returns hash of attributes (with appropriate attributes serialized),
|
@@ -217,8 +239,7 @@ module PaperTrail
|
|
217
239
|
#
|
218
240
|
# @api private
|
219
241
|
def object_attrs_for_paper_trail(is_touch)
|
220
|
-
attrs =
|
221
|
-
except(*@record.paper_trail_options[:skip])
|
242
|
+
attrs = nonskipped_attributes_before_change(is_touch)
|
222
243
|
AttributeSerializers::ObjectAttribute.new(@record.class).serialize(attrs)
|
223
244
|
attrs
|
224
245
|
end
|
@@ -237,9 +258,14 @@ module PaperTrail
|
|
237
258
|
# serialization here, using `PaperTrail.serializer`.
|
238
259
|
#
|
239
260
|
# @api private
|
261
|
+
# @param changes HashWithIndifferentAccess
|
240
262
|
def recordable_object_changes(changes)
|
241
263
|
if PaperTrail.config.object_changes_adapter&.respond_to?(:diff)
|
242
|
-
|
264
|
+
# We'd like to avoid the `to_hash` here, because it increases memory
|
265
|
+
# usage, but that would be a breaking change because
|
266
|
+
# `object_changes_adapter` expects a plain `Hash`, not a
|
267
|
+
# `HashWithIndifferentAccess`.
|
268
|
+
changes = PaperTrail.config.object_changes_adapter.diff(changes.to_hash)
|
243
269
|
end
|
244
270
|
|
245
271
|
if @record.class.paper_trail.version_class.object_changes_col_is_json?
|
@@ -284,7 +310,10 @@ module PaperTrail
|
|
284
310
|
AttributeSerializers::ObjectChangesAttribute.
|
285
311
|
new(@record.class).
|
286
312
|
serialize(changes)
|
287
|
-
|
313
|
+
|
314
|
+
# We'd like to convert this `HashWithIndifferentAccess` to a plain
|
315
|
+
# `Hash`, but we don't, to save memory.
|
316
|
+
changes
|
288
317
|
end
|
289
318
|
end
|
290
319
|
end
|
@@ -67,14 +67,14 @@ module PaperTrail
|
|
67
67
|
|
68
68
|
def record_create
|
69
69
|
return unless enabled?
|
70
|
-
event = Events::Create.new(@record, true)
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
71
|
+
build_version_on_create(in_after_callback: true).tap do |version|
|
72
|
+
version.save!
|
73
|
+
# Because the version object was created using version_class.new instead
|
74
|
+
# of versions_assoc.build?, the association cache is unaware. So, we
|
75
|
+
# invalidate the `versions` association cache with `reset`.
|
76
|
+
versions.reset
|
77
|
+
end
|
78
78
|
end
|
79
79
|
|
80
80
|
# PT-AT extends this method to add its transaction id.
|
@@ -119,19 +119,22 @@ module PaperTrail
|
|
119
119
|
# paper_trail-association_tracking
|
120
120
|
def record_update(force:, in_after_callback:, is_touch:)
|
121
121
|
return unless enabled?
|
122
|
-
event = Events::Update.new(@record, in_after_callback, is_touch, nil)
|
123
|
-
return unless force || event.changed_notably?
|
124
122
|
|
125
|
-
|
126
|
-
|
127
|
-
|
123
|
+
version = build_version_on_update(
|
124
|
+
force: force,
|
125
|
+
in_after_callback: in_after_callback,
|
126
|
+
is_touch: is_touch
|
127
|
+
)
|
128
|
+
return unless version
|
128
129
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
130
|
+
if version.save
|
131
|
+
# Because the version object was created using version_class.new instead
|
132
|
+
# of versions_assoc.build?, the association cache is unaware. So, we
|
133
|
+
# invalidate the `versions` association cache with `reset`.
|
134
|
+
versions.reset
|
134
135
|
version
|
136
|
+
else
|
137
|
+
log_version_errors(version, :update)
|
135
138
|
end
|
136
139
|
end
|
137
140
|
|
@@ -250,6 +253,35 @@ module PaperTrail
|
|
250
253
|
@record.send(@record.class.versions_association_name).reset
|
251
254
|
end
|
252
255
|
|
256
|
+
# @api private
|
257
|
+
def build_version_on_create(in_after_callback:)
|
258
|
+
event = Events::Create.new(@record, in_after_callback)
|
259
|
+
|
260
|
+
# Merge data from `Event` with data from PT-AT. We no longer use
|
261
|
+
# `data_for_create` but PT-AT still does.
|
262
|
+
data = event.data.merge!(data_for_create)
|
263
|
+
|
264
|
+
# Pure `version_class.new` reduces memory usage compared to `versions_assoc.build`
|
265
|
+
@record.class.paper_trail.version_class.new(data)
|
266
|
+
end
|
267
|
+
|
268
|
+
# @api private
|
269
|
+
def build_version_on_update(force:, in_after_callback:, is_touch:)
|
270
|
+
event = Events::Update.new(@record, in_after_callback, is_touch, nil)
|
271
|
+
return unless force || event.changed_notably?
|
272
|
+
|
273
|
+
# Merge data from `Event` with data from PT-AT. We no longer use
|
274
|
+
# `data_for_update` but PT-AT still does. To save memory, we use `merge!`
|
275
|
+
# instead of `merge`.
|
276
|
+
data = event.data.merge!(data_for_update)
|
277
|
+
|
278
|
+
# Using `version_class.new` reduces memory usage compared to
|
279
|
+
# `versions_assoc.build`. It's a trade-off though. We have to clear
|
280
|
+
# the association cache (see `versions.reset`) and that could cause an
|
281
|
+
# additional query in certain applications.
|
282
|
+
@record.class.paper_trail.version_class.new(data)
|
283
|
+
end
|
284
|
+
|
253
285
|
def log_version_errors(version, action)
|
254
286
|
version.logger&.warn(
|
255
287
|
"Unable to create version for #{action} of #{@record.class.name}" \
|
@@ -12,7 +12,12 @@ module PaperTrail
|
|
12
12
|
::YAML.load string
|
13
13
|
end
|
14
14
|
|
15
|
+
# @param object (Hash | HashWithIndifferentAccess) - Coming from
|
16
|
+
# `recordable_object` `object` will be a plain `Hash`. However, due to
|
17
|
+
# recent [memory optimizations](https://git.io/fjeYv), when coming from
|
18
|
+
# `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
|
15
19
|
def dump(object)
|
20
|
+
object = object.to_hash if object.is_a?(HashWithIndifferentAccess)
|
16
21
|
::YAML.dump object
|
17
22
|
end
|
18
23
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paper_trail
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 10.2.
|
4
|
+
version: 10.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andy Stewart
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2019-
|
13
|
+
date: 2019-03-14 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -102,6 +102,20 @@ dependencies:
|
|
102
102
|
- - "~>"
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: 0.9.4
|
105
|
+
- !ruby/object:Gem::Dependency
|
106
|
+
name: memory_profiler
|
107
|
+
requirement: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - "~>"
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: 0.9.12
|
112
|
+
type: :development
|
113
|
+
prerelease: false
|
114
|
+
version_requirements: !ruby/object:Gem::Requirement
|
115
|
+
requirements:
|
116
|
+
- - "~>"
|
117
|
+
- !ruby/object:Gem::Version
|
118
|
+
version: 0.9.12
|
105
119
|
- !ruby/object:Gem::Dependency
|
106
120
|
name: mysql2
|
107
121
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,14 +220,14 @@ dependencies:
|
|
206
220
|
requirements:
|
207
221
|
- - "~>"
|
208
222
|
- !ruby/object:Gem::Version
|
209
|
-
version:
|
223
|
+
version: 1.3.13
|
210
224
|
type: :development
|
211
225
|
prerelease: false
|
212
226
|
version_requirements: !ruby/object:Gem::Requirement
|
213
227
|
requirements:
|
214
228
|
- - "~>"
|
215
229
|
- !ruby/object:Gem::Version
|
216
|
-
version:
|
230
|
+
version: 1.3.13
|
217
231
|
description: |
|
218
232
|
Track changes to your models, for auditing or versioning. See how a model looked
|
219
233
|
at any stage in its lifecycle, revert it to any version, or restore it after it
|
@@ -284,8 +298,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
284
298
|
- !ruby/object:Gem::Version
|
285
299
|
version: 1.3.6
|
286
300
|
requirements: []
|
287
|
-
|
288
|
-
rubygems_version: 2.5.2.3
|
301
|
+
rubygems_version: 3.0.3
|
289
302
|
signing_key:
|
290
303
|
specification_version: 4
|
291
304
|
summary: Track changes to your models.
|