paper_trail 10.2.0 → 10.2.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|