paper_trail 12.0.0 → 12.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/generators/paper_trail/install/install_generator.rb +15 -3
- data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +4 -2
- data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +4 -2
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +6 -0
- data/lib/paper_trail/compatibility.rb +2 -2
- data/lib/paper_trail/errors.rb +33 -0
- data/lib/paper_trail/events/base.rb +47 -28
- data/lib/paper_trail/events/update.rb +23 -4
- data/lib/paper_trail/model_config.rb +49 -42
- data/lib/paper_trail/queries/versions/where_attribute_changes.rb +50 -0
- data/lib/paper_trail/queries/versions/where_object.rb +1 -1
- data/lib/paper_trail/queries/versions/where_object_changes.rb +7 -12
- data/lib/paper_trail/queries/versions/where_object_changes_from.rb +7 -15
- data/lib/paper_trail/queries/versions/where_object_changes_to.rb +57 -0
- data/lib/paper_trail/record_trail.rb +6 -4
- data/lib/paper_trail/reifier.rb +27 -10
- data/lib/paper_trail/request.rb +0 -3
- data/lib/paper_trail/serializers/json.rb +0 -18
- data/lib/paper_trail/serializers/yaml.rb +1 -21
- data/lib/paper_trail/version_concern.rb +47 -15
- data/lib/paper_trail/version_number.rb +1 -1
- data/lib/paper_trail.rb +5 -2
- metadata +64 -40
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e0f6ef6591b15081a76d93a70d959527f8cdc53cc3a6343ab6f1b7c40ef6695e
|
4
|
+
data.tar.gz: 202ee3126567ab99b39f8c76039fb7e20a4eb5e10e0e0880e867f19f228ace63
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c144126a2d8cec5537ef218b6637ee2ff6e6863de2e935facf6ad020dba6c2fb46bc5c13ed2ab674e9230c264d6e87905415ebc3c1e4bee5fbe50b1e73285663
|
7
|
+
data.tar.gz: 96530aebe8af35a95d47b6a5deadd3797b2d9255b28156f24a9f1be67fe629b254747d39ccad4d8f5d348d9fd74300b4b865ff9b32125c0951b14cf5d13ed60f
|
@@ -20,6 +20,12 @@ module PaperTrail
|
|
20
20
|
default: false,
|
21
21
|
desc: "Store changeset (diff) with each version"
|
22
22
|
)
|
23
|
+
class_option(
|
24
|
+
:uuid,
|
25
|
+
type: :boolean,
|
26
|
+
default: false,
|
27
|
+
desc: "Use uuid instead of bigint for item_id type (use only if tables use UUIDs)"
|
28
|
+
)
|
23
29
|
|
24
30
|
desc "Generates (but does not run) a migration to add a versions table." \
|
25
31
|
" See section 5.c. Generators in README.md for more information."
|
@@ -28,7 +34,8 @@ module PaperTrail
|
|
28
34
|
add_paper_trail_migration(
|
29
35
|
"create_versions",
|
30
36
|
item_type_options: item_type_options,
|
31
|
-
versions_table_options: versions_table_options
|
37
|
+
versions_table_options: versions_table_options,
|
38
|
+
item_id_type_options: item_id_type_options
|
32
39
|
)
|
33
40
|
if options.with_changes?
|
34
41
|
add_paper_trail_migration("add_object_changes_to_versions")
|
@@ -37,13 +44,18 @@ module PaperTrail
|
|
37
44
|
|
38
45
|
private
|
39
46
|
|
47
|
+
# To use uuid instead of integer for primary key
|
48
|
+
def item_id_type_options
|
49
|
+
options.uuid? ? "string" : "bigint"
|
50
|
+
end
|
51
|
+
|
40
52
|
# MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
|
41
53
|
# See https://github.com/paper-trail-gem/paper_trail/issues/651
|
42
54
|
def item_type_options
|
43
55
|
if mysql?
|
44
|
-
",
|
56
|
+
", null: false, limit: 191"
|
45
57
|
else
|
46
|
-
",
|
58
|
+
", null: false"
|
47
59
|
end
|
48
60
|
end
|
49
61
|
|
@@ -11,7 +11,7 @@ class CreateVersions < ActiveRecord::Migration<%= migration_version %>
|
|
11
11
|
def change
|
12
12
|
create_table :versions<%= versions_table_options %> do |t|
|
13
13
|
t.string :item_type<%= item_type_options %>
|
14
|
-
t
|
14
|
+
t.<%= item_id_type_options %> :item_id, null: false
|
15
15
|
t.string :event, null: false
|
16
16
|
t.string :whodunnit
|
17
17
|
t.text :object, limit: TEXT_BYTES
|
@@ -28,7 +28,9 @@ class CreateVersions < ActiveRecord::Migration<%= migration_version %>
|
|
28
28
|
# MySQL users should also upgrade to at least rails 4.2, which is the first
|
29
29
|
# version of ActiveRecord with support for fractional seconds in MySQL.
|
30
30
|
# (https://github.com/rails/rails/pull/14359)
|
31
|
-
#
|
31
|
+
#
|
32
|
+
# MySQL users should use the following line for `created_at`
|
33
|
+
# t.datetime :created_at, limit: 6
|
32
34
|
t.datetime :created_at
|
33
35
|
end
|
34
36
|
add_index :versions, %i(item_type item_id)
|
@@ -7,8 +7,10 @@ module PaperTrail
|
|
7
7
|
class UpdateItemSubtypeGenerator < MigrationGenerator
|
8
8
|
source_root File.expand_path("templates", __dir__)
|
9
9
|
|
10
|
-
desc
|
11
|
-
"
|
10
|
+
desc(
|
11
|
+
"Generates (but does not run) a migration to update item_subtype for "\
|
12
|
+
"STI entries in an existing versions table."
|
13
|
+
)
|
12
14
|
|
13
15
|
def create_migration_file
|
14
16
|
add_paper_trail_migration("update_versions_for_item_subtype", sti_type_options: options)
|
@@ -32,6 +32,12 @@ module PaperTrail
|
|
32
32
|
if defined_enums[attr] && val.is_a?(::String)
|
33
33
|
# Because PT 4 used to save the string version of enums to `object_changes`
|
34
34
|
val
|
35
|
+
elsif PaperTrail::RAILS_GTE_7_0 && val.is_a?(ActiveRecord::Type::Time::Value)
|
36
|
+
# Because Rails 7 time attribute throws a delegation error when you deserialize
|
37
|
+
# it with the factory.
|
38
|
+
# See ActiveRecord::Type::Time::Value crashes when loaded from YAML on rails 7.0
|
39
|
+
# https://github.com/rails/rails/issues/43966
|
40
|
+
val.instance_variable_get(:@time)
|
35
41
|
else
|
36
42
|
AttributeSerializerFactory.for(@klass, attr).deserialize(val)
|
37
43
|
end
|
@@ -8,7 +8,7 @@ module PaperTrail
|
|
8
8
|
#
|
9
9
|
# It is not safe to assume that a new version of rails will be compatible with
|
10
10
|
# PaperTrail. PT is only compatible with the versions of rails that it is
|
11
|
-
# tested against. See `.
|
11
|
+
# tested against. See `.github/workflows/test.yml`.
|
12
12
|
#
|
13
13
|
# However, as of
|
14
14
|
# [#1213](https://github.com/paper-trail-gem/paper_trail/pull/1213) our
|
@@ -18,7 +18,7 @@ module PaperTrail
|
|
18
18
|
# versions.
|
19
19
|
module Compatibility
|
20
20
|
ACTIVERECORD_GTE = ">= 5.2" # enforced in gemspec
|
21
|
-
ACTIVERECORD_LT = "<
|
21
|
+
ACTIVERECORD_LT = "< 7.1" # not enforced in gemspec
|
22
22
|
|
23
23
|
E_INCOMPATIBLE_AR = <<-EOS
|
24
24
|
PaperTrail %s is not compatible with ActiveRecord %s. We allow PT
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
# Generic PaperTrail exception.
|
5
|
+
# @api public
|
6
|
+
class Error < StandardError
|
7
|
+
end
|
8
|
+
|
9
|
+
# An unexpected option, perhaps a typo, was passed to a public API method.
|
10
|
+
# @api public
|
11
|
+
class InvalidOption < Error
|
12
|
+
end
|
13
|
+
|
14
|
+
# The application's database schema is not supported.
|
15
|
+
# @api public
|
16
|
+
class UnsupportedSchema < Error
|
17
|
+
end
|
18
|
+
|
19
|
+
# The application's database column type is not supported.
|
20
|
+
# @api public
|
21
|
+
class UnsupportedColumnType < UnsupportedSchema
|
22
|
+
def initialize(method:, expected:, actual:)
|
23
|
+
super(
|
24
|
+
format(
|
25
|
+
"%s expected %s column, got %s",
|
26
|
+
method,
|
27
|
+
expected,
|
28
|
+
actual
|
29
|
+
)
|
30
|
+
)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -109,19 +109,25 @@ module PaperTrail
|
|
109
109
|
@changed_in_latest_version ||= changes_in_latest_version.keys
|
110
110
|
end
|
111
111
|
|
112
|
-
#
|
113
|
-
# https://github.com/paper-trail-gem/paper_trail/pull/899
|
112
|
+
# Memoized to reduce memory usage
|
114
113
|
#
|
115
114
|
# @api private
|
116
115
|
def changes_in_latest_version
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
116
|
+
@changes_in_latest_version ||= load_changes_in_latest_version
|
117
|
+
end
|
118
|
+
|
119
|
+
# @api private
|
120
|
+
def evaluate_only
|
121
|
+
only = @record.paper_trail_options[:only].dup
|
122
|
+
# Remove Hash arguments and then evaluate whether the attributes (the
|
123
|
+
# keys of the hash) should also get pushed into the collection.
|
124
|
+
only.delete_if do |obj|
|
125
|
+
obj.is_a?(Hash) &&
|
126
|
+
obj.each { |attr, condition|
|
127
|
+
only << attr if condition.respond_to?(:call) && condition.call(@record)
|
128
|
+
}
|
124
129
|
end
|
130
|
+
only
|
125
131
|
end
|
126
132
|
|
127
133
|
# An attributed is "ignored" if it is listed in the `:ignore` option
|
@@ -134,6 +140,18 @@ module PaperTrail
|
|
134
140
|
ignored.any? && (changed_in_latest_version & ignored).any?
|
135
141
|
end
|
136
142
|
|
143
|
+
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
144
|
+
# https://github.com/paper-trail-gem/paper_trail/pull/899
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
def load_changes_in_latest_version
|
148
|
+
if @in_after_callback
|
149
|
+
@record.saved_changes
|
150
|
+
else
|
151
|
+
@record.changes
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
137
155
|
# PT 10 has a new optional column, `item_subtype`
|
138
156
|
#
|
139
157
|
# @api private
|
@@ -178,20 +196,28 @@ module PaperTrail
|
|
178
196
|
if value.respond_to?(:call)
|
179
197
|
value.call(@record)
|
180
198
|
elsif value.is_a?(Symbol) && @record.respond_to?(value, true)
|
181
|
-
|
182
|
-
# be sure to grab the current version.
|
183
|
-
if event != "create" &&
|
184
|
-
@record.has_attribute?(value) &&
|
185
|
-
attribute_changed_in_latest_version?(value)
|
186
|
-
attribute_in_previous_version(value, false)
|
187
|
-
else
|
188
|
-
@record.send(value)
|
189
|
-
end
|
199
|
+
metadatum_from_model_method(event, value)
|
190
200
|
else
|
191
201
|
value
|
192
202
|
end
|
193
203
|
end
|
194
204
|
|
205
|
+
# The model method can either be an attribute or a non-attribute method.
|
206
|
+
#
|
207
|
+
# If it is an attribute that is changing in an existing object,
|
208
|
+
# be sure to grab the correct version.
|
209
|
+
#
|
210
|
+
# @api private
|
211
|
+
def metadatum_from_model_method(event, method)
|
212
|
+
if event != "create" &&
|
213
|
+
@record.has_attribute?(method) &&
|
214
|
+
attribute_changed_in_latest_version?(method)
|
215
|
+
attribute_in_previous_version(method, false)
|
216
|
+
else
|
217
|
+
@record.send(method)
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
195
221
|
# @api private
|
196
222
|
def notable_changes
|
197
223
|
changes_in_latest_version.delete_if { |k, _v|
|
@@ -203,16 +229,9 @@ module PaperTrail
|
|
203
229
|
def notably_changed
|
204
230
|
# Memoized to reduce memory usage
|
205
231
|
@notably_changed ||= begin
|
206
|
-
only =
|
207
|
-
|
208
|
-
|
209
|
-
only.delete_if do |obj|
|
210
|
-
obj.is_a?(Hash) &&
|
211
|
-
obj.each { |attr, condition|
|
212
|
-
only << attr if condition.respond_to?(:call) && condition.call(@record)
|
213
|
-
}
|
214
|
-
end
|
215
|
-
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
232
|
+
only = evaluate_only
|
233
|
+
cani = changed_and_not_ignored
|
234
|
+
only.empty? ? cani : (cani & only)
|
216
235
|
end
|
217
236
|
end
|
218
237
|
|
@@ -35,16 +35,35 @@ module PaperTrail
|
|
35
35
|
if record_object?
|
36
36
|
data[:object] = recordable_object(@is_touch)
|
37
37
|
end
|
38
|
-
|
39
|
-
changes = @force_changes.nil? ? notable_changes : @force_changes
|
40
|
-
data[:object_changes] = prepare_object_changes(changes)
|
41
|
-
end
|
38
|
+
merge_object_changes_into(data)
|
42
39
|
merge_item_subtype_into(data)
|
43
40
|
merge_metadata_into(data)
|
44
41
|
end
|
45
42
|
|
43
|
+
# If it is a touch event, and changed are empty, it is assumed to be
|
44
|
+
# implicit `touch` mutation, and will a version is created.
|
45
|
+
#
|
46
|
+
# See https://github.com/rails/rails/commit/dcb825902d79d0f6baba956f7c6ec5767611353e
|
47
|
+
#
|
48
|
+
# @api private
|
49
|
+
def changed_notably?
|
50
|
+
if @is_touch && changes_in_latest_version.empty?
|
51
|
+
true
|
52
|
+
else
|
53
|
+
super
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
46
57
|
private
|
47
58
|
|
59
|
+
# @api private
|
60
|
+
def merge_object_changes_into(data)
|
61
|
+
if record_object_changes?
|
62
|
+
changes = @force_changes.nil? ? notable_changes : @force_changes
|
63
|
+
data[:object_changes] = prepare_object_changes(changes)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
48
67
|
# `touch` cannot record `object_changes` because rails' `touch` does not
|
49
68
|
# perform dirty-tracking. Specifically, methods from `Dirty`, like
|
50
69
|
# `saved_changes`, return the same values before and after `touch`.
|
@@ -18,11 +18,6 @@ module PaperTrail
|
|
18
18
|
`abstract_class`. This is fine, but all application models must be
|
19
19
|
configured to use concrete (not abstract) version models.
|
20
20
|
STR
|
21
|
-
E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE = <<~STR.squish.freeze
|
22
|
-
To use PaperTrail's per-model limit in your %s model, you must have an
|
23
|
-
item_subtype column in your versions table. See documentation sections
|
24
|
-
2.e.1 Per-model limit, and 4.b.1 The optional item_subtype column.
|
25
|
-
STR
|
26
21
|
DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION = <<~STR.squish
|
27
22
|
Passing versions association name as `has_paper_trail versions: %{versions_name}`
|
28
23
|
is deprecated. Use `has_paper_trail versions: {name: %{versions_name}}` instead.
|
@@ -45,22 +40,14 @@ module PaperTrail
|
|
45
40
|
@model_class.after_create { |r|
|
46
41
|
r.paper_trail.record_create if r.paper_trail.save_version?
|
47
42
|
}
|
48
|
-
|
49
|
-
@model_class.paper_trail_options[:on] << :create
|
43
|
+
append_option_uniquely(:on, :create)
|
50
44
|
end
|
51
45
|
|
52
46
|
# Adds a callback that records a version before or after a "destroy" event.
|
53
47
|
#
|
54
48
|
# @api public
|
55
49
|
def on_destroy(recording_order = "before")
|
56
|
-
|
57
|
-
raise ArgumentError, 'recording order can only be "after" or "before"'
|
58
|
-
end
|
59
|
-
|
60
|
-
if recording_order.to_s == "after" && cannot_record_after_destroy?
|
61
|
-
raise E_CANNOT_RECORD_AFTER_DESTROY
|
62
|
-
end
|
63
|
-
|
50
|
+
assert_valid_recording_order_for_on_destroy(recording_order)
|
64
51
|
@model_class.send(
|
65
52
|
"#{recording_order}_destroy",
|
66
53
|
lambda do |r|
|
@@ -68,9 +55,7 @@ module PaperTrail
|
|
68
55
|
r.paper_trail.record_destroy(recording_order)
|
69
56
|
end
|
70
57
|
)
|
71
|
-
|
72
|
-
return if @model_class.paper_trail_options[:on].include?(:destroy)
|
73
|
-
@model_class.paper_trail_options[:on] << :destroy
|
58
|
+
append_option_uniquely(:on, :destroy)
|
74
59
|
end
|
75
60
|
|
76
61
|
# Adds a callback that records a version after an "update" event.
|
@@ -92,19 +77,27 @@ module PaperTrail
|
|
92
77
|
@model_class.after_update { |r|
|
93
78
|
r.paper_trail.clear_version_instance
|
94
79
|
}
|
95
|
-
|
96
|
-
@model_class.paper_trail_options[:on] << :update
|
80
|
+
append_option_uniquely(:on, :update)
|
97
81
|
end
|
98
82
|
|
99
83
|
# Adds a callback that records a version after a "touch" event.
|
84
|
+
#
|
85
|
+
# Rails < 6.0 has a bug where dirty-tracking does not occur during
|
86
|
+
# a `touch`. (https://github.com/rails/rails/issues/33429) See also:
|
87
|
+
# https://github.com/paper-trail-gem/paper_trail/issues/1121
|
88
|
+
# https://github.com/paper-trail-gem/paper_trail/issues/1161
|
89
|
+
# https://github.com/paper-trail-gem/paper_trail/pull/1285
|
90
|
+
#
|
100
91
|
# @api public
|
101
92
|
def on_touch
|
102
93
|
@model_class.after_touch { |r|
|
103
|
-
r.paper_trail.
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
94
|
+
if r.paper_trail.save_version?
|
95
|
+
r.paper_trail.record_update(
|
96
|
+
force: RAILS_LT_6_0,
|
97
|
+
in_after_callback: true,
|
98
|
+
is_touch: true
|
99
|
+
)
|
100
|
+
end
|
108
101
|
}
|
109
102
|
end
|
110
103
|
|
@@ -117,7 +110,6 @@ module PaperTrail
|
|
117
110
|
@model_class.send :include, ::PaperTrail::Model::InstanceMethods
|
118
111
|
setup_options(options)
|
119
112
|
setup_associations(options)
|
120
|
-
check_presence_of_item_subtype_column(options)
|
121
113
|
@model_class.after_rollback { paper_trail.clear_rolled_back_versions }
|
122
114
|
setup_callbacks_from_options options[:on]
|
123
115
|
end
|
@@ -129,26 +121,37 @@ module PaperTrail
|
|
129
121
|
|
130
122
|
private
|
131
123
|
|
124
|
+
RAILS_LT_6_0 = ::ActiveRecord.gem_version < ::Gem::Version.new("6.0.0")
|
125
|
+
private_constant :RAILS_LT_6_0
|
126
|
+
|
127
|
+
# @api private
|
128
|
+
def append_option_uniquely(option, value)
|
129
|
+
collection = @model_class.paper_trail_options.fetch(option)
|
130
|
+
return if collection.include?(value)
|
131
|
+
collection << value
|
132
|
+
end
|
133
|
+
|
132
134
|
# Raises an error if the provided class is an `abstract_class`.
|
133
135
|
# @api private
|
134
136
|
def assert_concrete_activerecord_class(class_name)
|
135
137
|
if class_name.constantize.abstract_class?
|
136
|
-
raise format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
|
138
|
+
raise Error, format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
|
137
139
|
end
|
138
140
|
end
|
139
141
|
|
140
|
-
|
141
|
-
|
142
|
+
# @api private
|
143
|
+
def assert_valid_recording_order_for_on_destroy(recording_order)
|
144
|
+
unless %w[after before].include?(recording_order.to_s)
|
145
|
+
raise ArgumentError, 'recording order can only be "after" or "before"'
|
146
|
+
end
|
147
|
+
|
148
|
+
if recording_order.to_s == "after" && cannot_record_after_destroy?
|
149
|
+
raise Error, E_CANNOT_RECORD_AFTER_DESTROY
|
150
|
+
end
|
142
151
|
end
|
143
152
|
|
144
|
-
|
145
|
-
|
146
|
-
#
|
147
|
-
# @api private
|
148
|
-
def check_presence_of_item_subtype_column(options)
|
149
|
-
return unless options.key?(:limit)
|
150
|
-
return if version_class.item_subtype_column_present?
|
151
|
-
raise format(E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE, @model_class.name)
|
153
|
+
def cannot_record_after_destroy?
|
154
|
+
::ActiveRecord::Base.belongs_to_required_by_default
|
152
155
|
end
|
153
156
|
|
154
157
|
def check_version_class_name(options)
|
@@ -206,6 +209,14 @@ module PaperTrail
|
|
206
209
|
options
|
207
210
|
end
|
208
211
|
|
212
|
+
# Process an `ignore`, `skip`, or `only` option.
|
213
|
+
def event_attribute_option(option_name)
|
214
|
+
[@model_class.paper_trail_options[option_name]].
|
215
|
+
flatten.
|
216
|
+
compact.
|
217
|
+
map { |attr| attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s }
|
218
|
+
end
|
219
|
+
|
209
220
|
def get_versions_scope(options)
|
210
221
|
options[:versions][:scope] || -> { order(model.timestamp_sort_order) }
|
211
222
|
end
|
@@ -240,12 +251,8 @@ module PaperTrail
|
|
240
251
|
@model_class.paper_trail_options = options.dup
|
241
252
|
|
242
253
|
%i[ignore skip only].each do |k|
|
243
|
-
@model_class.paper_trail_options[k] =
|
244
|
-
flatten.
|
245
|
-
compact.
|
246
|
-
map { |attr| attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s }
|
254
|
+
@model_class.paper_trail_options[k] = event_attribute_option(k)
|
247
255
|
end
|
248
|
-
|
249
256
|
@model_class.paper_trail_options[:meta] ||= {}
|
250
257
|
end
|
251
258
|
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
module Queries
|
5
|
+
module Versions
|
6
|
+
# For public API documentation, see `where_attribute_changes` in
|
7
|
+
# `paper_trail/version_concern.rb`.
|
8
|
+
# @api private
|
9
|
+
class WhereAttributeChanges
|
10
|
+
# - version_model_class - The class that VersionConcern was mixed into.
|
11
|
+
# - attribute - An attribute that changed. See the public API
|
12
|
+
# documentation for details.
|
13
|
+
# @api private
|
14
|
+
def initialize(version_model_class, attribute)
|
15
|
+
@version_model_class = version_model_class
|
16
|
+
@attribute = attribute
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def execute
|
21
|
+
if PaperTrail.config.object_changes_adapter.respond_to?(:where_attribute_changes)
|
22
|
+
return PaperTrail.config.object_changes_adapter.where_attribute_changes(
|
23
|
+
@version_model_class, @attribute
|
24
|
+
)
|
25
|
+
end
|
26
|
+
column_type = @version_model_class.columns_hash["object_changes"].type
|
27
|
+
case column_type
|
28
|
+
when :jsonb, :json
|
29
|
+
json
|
30
|
+
else
|
31
|
+
raise UnsupportedColumnType.new(
|
32
|
+
method: "where_attribute_changes",
|
33
|
+
expected: "json or jsonb",
|
34
|
+
actual: column_type
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
def json
|
43
|
+
sql = "object_changes -> ? IS NOT NULL"
|
44
|
+
|
45
|
+
@version_model_class.where(sql, @attribute)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -19,7 +19,7 @@ module PaperTrail
|
|
19
19
|
# @api private
|
20
20
|
def execute
|
21
21
|
column = @version_model_class.columns_hash["object"]
|
22
|
-
raise "where_object
|
22
|
+
raise Error, "where_object requires an object column" unless column
|
23
23
|
|
24
24
|
case column.type
|
25
25
|
when :jsonb
|
@@ -28,13 +28,18 @@ module PaperTrail
|
|
28
28
|
@version_model_class, @attributes
|
29
29
|
)
|
30
30
|
end
|
31
|
-
|
31
|
+
column_type = @version_model_class.columns_hash["object_changes"].type
|
32
|
+
case column_type
|
32
33
|
when :jsonb
|
33
34
|
jsonb
|
34
35
|
when :json
|
35
36
|
json
|
36
37
|
else
|
37
|
-
|
38
|
+
raise UnsupportedColumnType.new(
|
39
|
+
method: "where_object_changes",
|
40
|
+
expected: "json or jsonb",
|
41
|
+
actual: column_type
|
42
|
+
)
|
38
43
|
end
|
39
44
|
end
|
40
45
|
|
@@ -59,16 +64,6 @@ module PaperTrail
|
|
59
64
|
@attributes.each { |field, value| @attributes[field] = [value] }
|
60
65
|
@version_model_class.where("object_changes @> ?", @attributes.to_json)
|
61
66
|
end
|
62
|
-
|
63
|
-
# @api private
|
64
|
-
def text
|
65
|
-
arel_field = @version_model_class.arel_table[:object_changes]
|
66
|
-
where_conditions = @attributes.map { |field, value|
|
67
|
-
::PaperTrail.serializer.where_object_changes_condition(arel_field, field, value)
|
68
|
-
}
|
69
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
70
|
-
@version_model_class.where(where_conditions)
|
71
|
-
end
|
72
67
|
end
|
73
68
|
end
|
74
69
|
end
|
@@ -23,12 +23,16 @@ module PaperTrail
|
|
23
23
|
@version_model_class, @attributes
|
24
24
|
)
|
25
25
|
end
|
26
|
-
|
27
|
-
case
|
26
|
+
column_type = @version_model_class.columns_hash["object_changes"].type
|
27
|
+
case column_type
|
28
28
|
when :jsonb, :json
|
29
29
|
json
|
30
30
|
else
|
31
|
-
|
31
|
+
raise UnsupportedColumnType.new(
|
32
|
+
method: "where_object_changes_from",
|
33
|
+
expected: "json or jsonb",
|
34
|
+
actual: column_type
|
35
|
+
)
|
32
36
|
end
|
33
37
|
end
|
34
38
|
|
@@ -47,18 +51,6 @@ module PaperTrail
|
|
47
51
|
sql = predicates.join(" and ")
|
48
52
|
@version_model_class.where(sql, *values)
|
49
53
|
end
|
50
|
-
|
51
|
-
# @api private
|
52
|
-
def text
|
53
|
-
arel_field = @version_model_class.arel_table[:object_changes]
|
54
|
-
|
55
|
-
where_conditions = @attributes.map do |field, value|
|
56
|
-
::PaperTrail.serializer.where_object_changes_from_condition(arel_field, field, value)
|
57
|
-
end
|
58
|
-
|
59
|
-
where_conditions = where_conditions.reduce { |a, e| a.and(e) }
|
60
|
-
@version_model_class.where(where_conditions)
|
61
|
-
end
|
62
54
|
end
|
63
55
|
end
|
64
56
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
module Queries
|
5
|
+
module Versions
|
6
|
+
# For public API documentation, see `where_object_changes_to` in
|
7
|
+
# `paper_trail/version_concern.rb`.
|
8
|
+
# @api private
|
9
|
+
class WhereObjectChangesTo
|
10
|
+
# - version_model_class - The class that VersionConcern was mixed into.
|
11
|
+
# - attributes - A `Hash` of attributes and values. See the public API
|
12
|
+
# documentation for details.
|
13
|
+
# @api private
|
14
|
+
def initialize(version_model_class, attributes)
|
15
|
+
@version_model_class = version_model_class
|
16
|
+
@attributes = attributes
|
17
|
+
end
|
18
|
+
|
19
|
+
# @api private
|
20
|
+
def execute
|
21
|
+
if PaperTrail.config.object_changes_adapter.respond_to?(:where_object_changes_to)
|
22
|
+
return PaperTrail.config.object_changes_adapter.where_object_changes_to(
|
23
|
+
@version_model_class, @attributes
|
24
|
+
)
|
25
|
+
end
|
26
|
+
column_type = @version_model_class.columns_hash["object_changes"].type
|
27
|
+
case column_type
|
28
|
+
when :jsonb, :json
|
29
|
+
json
|
30
|
+
else
|
31
|
+
raise UnsupportedColumnType.new(
|
32
|
+
method: "where_object_changes_to",
|
33
|
+
expected: "json or jsonb",
|
34
|
+
actual: column_type
|
35
|
+
)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
def json
|
43
|
+
predicates = []
|
44
|
+
values = []
|
45
|
+
@attributes.each do |field, value|
|
46
|
+
predicates.push(
|
47
|
+
"(object_changes->>? ILIKE ?)"
|
48
|
+
)
|
49
|
+
values.concat([field, "[%#{value.to_json}]"])
|
50
|
+
end
|
51
|
+
sql = predicates.join(" and ")
|
52
|
+
@version_model_class.where(sql, *values)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -194,15 +194,17 @@ module PaperTrail
|
|
194
194
|
# Save, and create a version record regardless of options such as `:on`,
|
195
195
|
# `:if`, or `:unless`.
|
196
196
|
#
|
197
|
-
#
|
197
|
+
# `in_after_callback`: Indicates if this method is being called within an
|
198
|
+
# `after` callback. Defaults to `false`.
|
199
|
+
# `options`: Optional arguments passed to `save`.
|
198
200
|
#
|
199
201
|
# This is an "update" event. That is, we record the same data we would in
|
200
202
|
# the case of a normal AR `update`.
|
201
|
-
def save_with_version(**options)
|
203
|
+
def save_with_version(in_after_callback: false, **options)
|
202
204
|
::PaperTrail.request(enabled: false) do
|
203
205
|
@record.save(**options)
|
204
206
|
end
|
205
|
-
record_update(force: true, in_after_callback:
|
207
|
+
record_update(force: true, in_after_callback: in_after_callback, is_touch: false)
|
206
208
|
end
|
207
209
|
|
208
210
|
# Like the `update_column` method from `ActiveRecord::Persistence`, but also
|
@@ -283,7 +285,7 @@ module PaperTrail
|
|
283
285
|
def log_version_errors(version, action)
|
284
286
|
version.logger&.warn(
|
285
287
|
"Unable to create version for #{action} of #{@record.class.name}" \
|
286
|
-
|
288
|
+
"##{@record.id}: " + version.errors.full_messages.join(", ")
|
287
289
|
)
|
288
290
|
end
|
289
291
|
|
data/lib/paper_trail/reifier.rb
CHANGED
@@ -60,9 +60,7 @@ module PaperTrail
|
|
60
60
|
model = if options[:dup] == true || version.event == "destroy"
|
61
61
|
klass.new
|
62
62
|
else
|
63
|
-
|
64
|
-
|
65
|
-
version.item || klass.unscoped.where(find_cond).first || klass.new
|
63
|
+
version.item || init_model_by_finding_item_id(klass, version) || klass.new
|
66
64
|
end
|
67
65
|
|
68
66
|
if options[:unversioned_attributes] == :nil && !model.new_record?
|
@@ -72,6 +70,11 @@ module PaperTrail
|
|
72
70
|
model
|
73
71
|
end
|
74
72
|
|
73
|
+
# @api private
|
74
|
+
def init_model_by_finding_item_id(klass, version)
|
75
|
+
klass.unscoped.where(klass.primary_key => version.item_id).first
|
76
|
+
end
|
77
|
+
|
75
78
|
# Look for attributes that exist in `model` and not in this version.
|
76
79
|
# These attributes should be set to nil. Modifies `attrs`.
|
77
80
|
# @api private
|
@@ -109,21 +112,35 @@ module PaperTrail
|
|
109
112
|
end
|
110
113
|
|
111
114
|
# Given a `version`, return the class to reify. This method supports
|
112
|
-
# Single Table Inheritance (STI) with custom inheritance columns
|
115
|
+
# Single Table Inheritance (STI) with custom inheritance columns and
|
116
|
+
# custom inheritance column values.
|
113
117
|
#
|
114
118
|
# For example, imagine a `version` whose `item_type` is "Animal". The
|
115
119
|
# `animals` table is an STI table (it has cats and dogs) and it has a
|
116
120
|
# custom inheritance column, `species`. If `attrs["species"]` is "Dog",
|
117
121
|
# this method returns the constant `Dog`. If `attrs["species"]` is blank,
|
118
|
-
# this method returns the constant `Animal`.
|
119
|
-
# example in action in `spec/models/animal_spec.rb`.
|
122
|
+
# this method returns the constant `Animal`.
|
120
123
|
#
|
121
|
-
#
|
124
|
+
# The values contained in the inheritance columns may be non-camelized
|
125
|
+
# strings (e.g. 'dog' instead of 'Dog'). To reify classes in this case
|
126
|
+
# we need to call the parents class `sti_class_for` method to retrieve
|
127
|
+
# the correct record class.
|
128
|
+
#
|
129
|
+
# You can see these particular examples in action in
|
130
|
+
# `spec/models/animal_spec.rb` and `spec/models/plant_spec.rb`
|
122
131
|
def version_reification_class(version, attrs)
|
123
|
-
|
132
|
+
clazz = version.item_type.constantize
|
133
|
+
inheritance_column_name = clazz.inheritance_column
|
124
134
|
inher_col_value = attrs[inheritance_column_name]
|
125
|
-
|
126
|
-
|
135
|
+
return clazz if inher_col_value.blank?
|
136
|
+
|
137
|
+
# Rails 6.1 adds a public method for clients to use to customize STI classes. If that
|
138
|
+
# method is not available, fall back to using the private one
|
139
|
+
if clazz.public_methods.include?(:sti_class_for)
|
140
|
+
return clazz.sti_class_for(inher_col_value)
|
141
|
+
end
|
142
|
+
|
143
|
+
clazz.send(:find_sti_class, inher_col_value)
|
127
144
|
end
|
128
145
|
end
|
129
146
|
end
|
data/lib/paper_trail/request.rb
CHANGED
@@ -12,9 +12,6 @@ module PaperTrail
|
|
12
12
|
#
|
13
13
|
# @api private
|
14
14
|
module Request
|
15
|
-
class InvalidOption < RuntimeError
|
16
|
-
end
|
17
|
-
|
18
15
|
class << self
|
19
16
|
# Sets any data from the controller that you want PaperTrail to store.
|
20
17
|
# See also `PaperTrail::Rails::Controller#info_for_paper_trail`.
|
@@ -31,24 +31,6 @@ module PaperTrail
|
|
31
31
|
arel_field.matches("%\"#{field}\":#{json_value}%")
|
32
32
|
end
|
33
33
|
end
|
34
|
-
|
35
|
-
def where_object_changes_condition(*)
|
36
|
-
raise <<-STR.squish.freeze
|
37
|
-
where_object_changes no longer supports reading JSON from a text
|
38
|
-
column. The old implementation was inaccurate, returning more records
|
39
|
-
than you wanted. This feature was deprecated in 7.1.0 and removed in
|
40
|
-
8.0.0. The json and jsonb datatypes are still supported. See the
|
41
|
-
discussion at https://github.com/paper-trail-gem/paper_trail/issues/803
|
42
|
-
STR
|
43
|
-
end
|
44
|
-
|
45
|
-
# Raises an exception as this operation is not allowed from text columns.
|
46
|
-
def where_object_changes_from_condition(*)
|
47
|
-
raise <<-STR.squish.freeze
|
48
|
-
where_object_changes_from does not support reading JSON from a text
|
49
|
-
column. The json and jsonb datatypes are supported.
|
50
|
-
STR
|
51
|
-
end
|
52
34
|
end
|
53
35
|
end
|
54
36
|
end
|
@@ -9,7 +9,7 @@ module PaperTrail
|
|
9
9
|
extend self # makes all instance methods become module methods as well
|
10
10
|
|
11
11
|
def load(string)
|
12
|
-
::YAML.
|
12
|
+
::YAML.respond_to?(:unsafe_load) ? ::YAML.unsafe_load(string) : ::YAML.load(string)
|
13
13
|
end
|
14
14
|
|
15
15
|
# @param object (Hash | HashWithIndifferentAccess) - Coming from
|
@@ -26,26 +26,6 @@ module PaperTrail
|
|
26
26
|
def where_object_condition(arel_field, field, value)
|
27
27
|
arel_field.matches("%\n#{field}: #{value}\n%")
|
28
28
|
end
|
29
|
-
|
30
|
-
# Returns a SQL LIKE condition to be used to match the given field and
|
31
|
-
# value in the serialized `object_changes`.
|
32
|
-
def where_object_changes_condition(*)
|
33
|
-
raise <<-STR.squish.freeze
|
34
|
-
where_object_changes no longer supports reading YAML from a text
|
35
|
-
column. The old implementation was inaccurate, returning more records
|
36
|
-
than you wanted. This feature was deprecated in 8.1.0 and removed in
|
37
|
-
9.0.0. The json and jsonb datatypes are still supported. See
|
38
|
-
discussion at https://github.com/paper-trail-gem/paper_trail/pull/997
|
39
|
-
STR
|
40
|
-
end
|
41
|
-
|
42
|
-
# Raises an exception as this operation is not allowed with YAML.
|
43
|
-
def where_object_changes_from_condition(*)
|
44
|
-
raise <<-STR.squish.freeze
|
45
|
-
where_object_changes_from does not support reading YAML from a text
|
46
|
-
column. The json and jsonb datatypes are supported.
|
47
|
-
STR
|
48
|
-
end
|
49
29
|
end
|
50
30
|
end
|
51
31
|
end
|
@@ -1,9 +1,11 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require "paper_trail/attribute_serializers/object_changes_attribute"
|
4
|
+
require "paper_trail/queries/versions/where_attribute_changes"
|
4
5
|
require "paper_trail/queries/versions/where_object"
|
5
6
|
require "paper_trail/queries/versions/where_object_changes"
|
6
7
|
require "paper_trail/queries/versions/where_object_changes_from"
|
8
|
+
require "paper_trail/queries/versions/where_object_changes_to"
|
7
9
|
|
8
10
|
module PaperTrail
|
9
11
|
# Originally, PaperTrail did not provide this module, and all of this
|
@@ -14,17 +16,13 @@ module PaperTrail
|
|
14
16
|
extend ::ActiveSupport::Concern
|
15
17
|
|
16
18
|
included do
|
17
|
-
belongs_to :item, polymorphic: true, optional: true
|
19
|
+
belongs_to :item, polymorphic: true, optional: true, inverse_of: false
|
18
20
|
validates_presence_of :event
|
19
21
|
after_create :enforce_version_limit!
|
20
22
|
end
|
21
23
|
|
22
24
|
# :nodoc:
|
23
25
|
module ClassMethods
|
24
|
-
def item_subtype_column_present?
|
25
|
-
column_names.include?("item_subtype")
|
26
|
-
end
|
27
|
-
|
28
26
|
def with_item_keys(item_type, item_id)
|
29
27
|
where item_type: item_type, item_id: item_id
|
30
28
|
end
|
@@ -42,7 +40,7 @@ module PaperTrail
|
|
42
40
|
end
|
43
41
|
|
44
42
|
def not_creates
|
45
|
-
where
|
43
|
+
where.not(event: "create")
|
46
44
|
end
|
47
45
|
|
48
46
|
def between(start_time, end_time)
|
@@ -60,6 +58,18 @@ module PaperTrail
|
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
61
|
+
# Given an attribute like `"name"`, query the `versions.object_changes`
|
62
|
+
# column for any changes that modified the provided attribute.
|
63
|
+
#
|
64
|
+
# @api public
|
65
|
+
def where_attribute_changes(attribute)
|
66
|
+
unless attribute.is_a?(String) || attribute.is_a?(Symbol)
|
67
|
+
raise ArgumentError, "expected to receive a String or Symbol"
|
68
|
+
end
|
69
|
+
|
70
|
+
Queries::Versions::WhereAttributeChanges.new(self, attribute).execute
|
71
|
+
end
|
72
|
+
|
63
73
|
# Given a hash of attributes like `name: 'Joan'`, query the
|
64
74
|
# `versions.objects` column.
|
65
75
|
#
|
@@ -131,6 +141,21 @@ module PaperTrail
|
|
131
141
|
Queries::Versions::WhereObjectChangesFrom.new(self, args).execute
|
132
142
|
end
|
133
143
|
|
144
|
+
# Given a hash of attributes like `name: 'Joan'`, query the
|
145
|
+
# `versions.objects_changes` column for changes where the version changed
|
146
|
+
# to the hash of attributes from other values.
|
147
|
+
#
|
148
|
+
# This is useful for finding versions where the attribute started with an
|
149
|
+
# unknown value and changed to a known value. This is in comparison to
|
150
|
+
# `where_object_changes` which will find both the changes before and
|
151
|
+
# after.
|
152
|
+
#
|
153
|
+
# @api public
|
154
|
+
def where_object_changes_to(args = {})
|
155
|
+
raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
|
156
|
+
Queries::Versions::WhereObjectChangesTo.new(self, args).execute
|
157
|
+
end
|
158
|
+
|
134
159
|
def primary_key_is_int?
|
135
160
|
@primary_key_is_int ||= columns_hash[primary_key].type == :integer
|
136
161
|
rescue StandardError # TODO: Rescue something more specific
|
@@ -237,7 +262,7 @@ module PaperTrail
|
|
237
262
|
#
|
238
263
|
def reify(options = {})
|
239
264
|
unless self.class.column_names.include? "object"
|
240
|
-
raise "reify
|
265
|
+
raise Error, "reify requires an object column"
|
241
266
|
end
|
242
267
|
return nil if object.nil?
|
243
268
|
::PaperTrail::Reifier.reify(self, options)
|
@@ -350,16 +375,23 @@ module PaperTrail
|
|
350
375
|
# The version limit can be global or per-model.
|
351
376
|
#
|
352
377
|
# @api private
|
353
|
-
#
|
354
|
-
# TODO: Duplication: similar `constantize` in Reifier#version_reification_class
|
355
378
|
def version_limit
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
379
|
+
klass = item.class
|
380
|
+
if limit_option?(klass)
|
381
|
+
klass.paper_trail_options[:limit]
|
382
|
+
elsif base_class_limit_option?(klass)
|
383
|
+
klass.base_class.paper_trail_options[:limit]
|
384
|
+
else
|
385
|
+
PaperTrail.config.version_limit
|
361
386
|
end
|
362
|
-
|
387
|
+
end
|
388
|
+
|
389
|
+
def limit_option?(klass)
|
390
|
+
klass.respond_to?(:paper_trail_options) && klass.paper_trail_options.key?(:limit)
|
391
|
+
end
|
392
|
+
|
393
|
+
def base_class_limit_option?(klass)
|
394
|
+
klass.respond_to?(:base_class) && limit_option?(klass.base_class)
|
363
395
|
end
|
364
396
|
end
|
365
397
|
end
|
data/lib/paper_trail.rb
CHANGED
@@ -8,6 +8,7 @@
|
|
8
8
|
# can revisit this decision.
|
9
9
|
require "active_support/all"
|
10
10
|
|
11
|
+
require "paper_trail/errors"
|
11
12
|
require "paper_trail/cleaner"
|
12
13
|
require "paper_trail/compatibility"
|
13
14
|
require "paper_trail/config"
|
@@ -25,6 +26,8 @@ module PaperTrail
|
|
25
26
|
named created_at.
|
26
27
|
EOS
|
27
28
|
|
29
|
+
RAILS_GTE_7_0 = ::ActiveRecord.gem_version >= ::Gem::Version.new("7.0.0")
|
30
|
+
|
28
31
|
extend PaperTrail::Cleaner
|
29
32
|
|
30
33
|
class << self
|
@@ -68,7 +71,7 @@ module PaperTrail
|
|
68
71
|
#
|
69
72
|
# @api public
|
70
73
|
def request(options = nil, &block)
|
71
|
-
if options.nil? && !
|
74
|
+
if options.nil? && !block
|
72
75
|
Request
|
73
76
|
else
|
74
77
|
Request.with(options, &block)
|
@@ -78,7 +81,7 @@ module PaperTrail
|
|
78
81
|
# Set the field which records when a version was created.
|
79
82
|
# @api public
|
80
83
|
def timestamp_field=(_field_name)
|
81
|
-
raise
|
84
|
+
raise Error, E_TIMESTAMP_FIELD_CONFIG
|
82
85
|
end
|
83
86
|
|
84
87
|
# Set the PaperTrail serializer. This setting affects all threads.
|
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: 12.
|
4
|
+
version: 12.3.0
|
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:
|
13
|
+
date: 2022-03-13 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -46,42 +46,42 @@ dependencies:
|
|
46
46
|
requirements:
|
47
47
|
- - "~>"
|
48
48
|
- !ruby/object:Gem::Version
|
49
|
-
version:
|
49
|
+
version: 2.4.1
|
50
50
|
type: :development
|
51
51
|
prerelease: false
|
52
52
|
version_requirements: !ruby/object:Gem::Requirement
|
53
53
|
requirements:
|
54
54
|
- - "~>"
|
55
55
|
- !ruby/object:Gem::Version
|
56
|
-
version:
|
56
|
+
version: 2.4.1
|
57
57
|
- !ruby/object:Gem::Dependency
|
58
58
|
name: byebug
|
59
59
|
requirement: !ruby/object:Gem::Requirement
|
60
60
|
requirements:
|
61
61
|
- - "~>"
|
62
62
|
- !ruby/object:Gem::Version
|
63
|
-
version: '11.
|
63
|
+
version: '11.1'
|
64
64
|
type: :development
|
65
65
|
prerelease: false
|
66
66
|
version_requirements: !ruby/object:Gem::Requirement
|
67
67
|
requirements:
|
68
68
|
- - "~>"
|
69
69
|
- !ruby/object:Gem::Version
|
70
|
-
version: '11.
|
70
|
+
version: '11.1'
|
71
71
|
- !ruby/object:Gem::Dependency
|
72
72
|
name: ffaker
|
73
73
|
requirement: !ruby/object:Gem::Requirement
|
74
74
|
requirements:
|
75
75
|
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version: '2.
|
77
|
+
version: '2.20'
|
78
78
|
type: :development
|
79
79
|
prerelease: false
|
80
80
|
version_requirements: !ruby/object:Gem::Requirement
|
81
81
|
requirements:
|
82
82
|
- - "~>"
|
83
83
|
- !ruby/object:Gem::Version
|
84
|
-
version: '2.
|
84
|
+
version: '2.20'
|
85
85
|
- !ruby/object:Gem::Dependency
|
86
86
|
name: generator_spec
|
87
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -102,14 +102,14 @@ dependencies:
|
|
102
102
|
requirements:
|
103
103
|
- - "~>"
|
104
104
|
- !ruby/object:Gem::Version
|
105
|
-
version: 0.
|
105
|
+
version: 1.0.0
|
106
106
|
type: :development
|
107
107
|
prerelease: false
|
108
108
|
version_requirements: !ruby/object:Gem::Requirement
|
109
109
|
requirements:
|
110
110
|
- - "~>"
|
111
111
|
- !ruby/object:Gem::Version
|
112
|
-
version: 0.
|
112
|
+
version: 1.0.0
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: rails
|
115
115
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,118 +144,140 @@ dependencies:
|
|
144
144
|
requirements:
|
145
145
|
- - "~>"
|
146
146
|
- !ruby/object:Gem::Version
|
147
|
-
version:
|
147
|
+
version: 5.0.2
|
148
148
|
type: :development
|
149
149
|
prerelease: false
|
150
150
|
version_requirements: !ruby/object:Gem::Requirement
|
151
151
|
requirements:
|
152
152
|
- - "~>"
|
153
153
|
- !ruby/object:Gem::Version
|
154
|
-
version:
|
154
|
+
version: 5.0.2
|
155
155
|
- !ruby/object:Gem::Dependency
|
156
156
|
name: rubocop
|
157
157
|
requirement: !ruby/object:Gem::Requirement
|
158
158
|
requirements:
|
159
159
|
- - "~>"
|
160
160
|
- !ruby/object:Gem::Version
|
161
|
-
version: 1.
|
161
|
+
version: 1.22.2
|
162
162
|
type: :development
|
163
163
|
prerelease: false
|
164
164
|
version_requirements: !ruby/object:Gem::Requirement
|
165
165
|
requirements:
|
166
166
|
- - "~>"
|
167
167
|
- !ruby/object:Gem::Version
|
168
|
-
version: 1.
|
168
|
+
version: 1.22.2
|
169
169
|
- !ruby/object:Gem::Dependency
|
170
|
-
name: rubocop-
|
170
|
+
name: rubocop-packaging
|
171
171
|
requirement: !ruby/object:Gem::Requirement
|
172
172
|
requirements:
|
173
173
|
- - "~>"
|
174
174
|
- !ruby/object:Gem::Version
|
175
|
-
version:
|
175
|
+
version: 0.5.1
|
176
176
|
type: :development
|
177
177
|
prerelease: false
|
178
178
|
version_requirements: !ruby/object:Gem::Requirement
|
179
179
|
requirements:
|
180
180
|
- - "~>"
|
181
181
|
- !ruby/object:Gem::Version
|
182
|
-
version:
|
182
|
+
version: 0.5.1
|
183
183
|
- !ruby/object:Gem::Dependency
|
184
|
-
name: rubocop-
|
184
|
+
name: rubocop-performance
|
185
185
|
requirement: !ruby/object:Gem::Requirement
|
186
186
|
requirements:
|
187
187
|
- - "~>"
|
188
188
|
- !ruby/object:Gem::Version
|
189
|
-
version:
|
189
|
+
version: 1.11.5
|
190
190
|
type: :development
|
191
191
|
prerelease: false
|
192
192
|
version_requirements: !ruby/object:Gem::Requirement
|
193
193
|
requirements:
|
194
194
|
- - "~>"
|
195
195
|
- !ruby/object:Gem::Version
|
196
|
-
version:
|
196
|
+
version: 1.11.5
|
197
197
|
- !ruby/object:Gem::Dependency
|
198
|
-
name: rubocop-
|
198
|
+
name: rubocop-rails
|
199
|
+
requirement: !ruby/object:Gem::Requirement
|
200
|
+
requirements:
|
201
|
+
- - "~>"
|
202
|
+
- !ruby/object:Gem::Version
|
203
|
+
version: 2.12.4
|
204
|
+
type: :development
|
205
|
+
prerelease: false
|
206
|
+
version_requirements: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - "~>"
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 2.12.4
|
211
|
+
- !ruby/object:Gem::Dependency
|
212
|
+
name: rubocop-rake
|
199
213
|
requirement: !ruby/object:Gem::Requirement
|
200
214
|
requirements:
|
201
215
|
- - "~>"
|
202
216
|
- !ruby/object:Gem::Version
|
203
|
-
version:
|
217
|
+
version: 0.6.0
|
204
218
|
type: :development
|
205
219
|
prerelease: false
|
206
220
|
version_requirements: !ruby/object:Gem::Requirement
|
207
221
|
requirements:
|
208
222
|
- - "~>"
|
209
223
|
- !ruby/object:Gem::Version
|
210
|
-
version:
|
224
|
+
version: 0.6.0
|
211
225
|
- !ruby/object:Gem::Dependency
|
212
226
|
name: rubocop-rspec
|
213
227
|
requirement: !ruby/object:Gem::Requirement
|
214
228
|
requirements:
|
215
229
|
- - "~>"
|
216
230
|
- !ruby/object:Gem::Version
|
217
|
-
version: 2.
|
231
|
+
version: 2.5.0
|
218
232
|
type: :development
|
219
233
|
prerelease: false
|
220
234
|
version_requirements: !ruby/object:Gem::Requirement
|
221
235
|
requirements:
|
222
236
|
- - "~>"
|
223
237
|
- !ruby/object:Gem::Version
|
224
|
-
version: 2.
|
238
|
+
version: 2.5.0
|
239
|
+
- !ruby/object:Gem::Dependency
|
240
|
+
name: simplecov
|
241
|
+
requirement: !ruby/object:Gem::Requirement
|
242
|
+
requirements:
|
243
|
+
- - "~>"
|
244
|
+
- !ruby/object:Gem::Version
|
245
|
+
version: 0.21.2
|
246
|
+
type: :development
|
247
|
+
prerelease: false
|
248
|
+
version_requirements: !ruby/object:Gem::Requirement
|
249
|
+
requirements:
|
250
|
+
- - "~>"
|
251
|
+
- !ruby/object:Gem::Version
|
252
|
+
version: 0.21.2
|
225
253
|
- !ruby/object:Gem::Dependency
|
226
254
|
name: mysql2
|
227
255
|
requirement: !ruby/object:Gem::Requirement
|
228
256
|
requirements:
|
229
257
|
- - "~>"
|
230
258
|
- !ruby/object:Gem::Version
|
231
|
-
version:
|
259
|
+
version: 0.5.3
|
232
260
|
type: :development
|
233
261
|
prerelease: false
|
234
262
|
version_requirements: !ruby/object:Gem::Requirement
|
235
263
|
requirements:
|
236
264
|
- - "~>"
|
237
265
|
- !ruby/object:Gem::Version
|
238
|
-
version:
|
266
|
+
version: 0.5.3
|
239
267
|
- !ruby/object:Gem::Dependency
|
240
268
|
name: pg
|
241
269
|
requirement: !ruby/object:Gem::Requirement
|
242
270
|
requirements:
|
243
|
-
- - "
|
244
|
-
- !ruby/object:Gem::Version
|
245
|
-
version: '0.18'
|
246
|
-
- - "<"
|
271
|
+
- - "~>"
|
247
272
|
- !ruby/object:Gem::Version
|
248
|
-
version: '2
|
273
|
+
version: '1.2'
|
249
274
|
type: :development
|
250
275
|
prerelease: false
|
251
276
|
version_requirements: !ruby/object:Gem::Requirement
|
252
277
|
requirements:
|
253
|
-
- - "
|
254
|
-
- !ruby/object:Gem::Version
|
255
|
-
version: '0.18'
|
256
|
-
- - "<"
|
278
|
+
- - "~>"
|
257
279
|
- !ruby/object:Gem::Version
|
258
|
-
version: '2
|
280
|
+
version: '1.2'
|
259
281
|
- !ruby/object:Gem::Dependency
|
260
282
|
name: sqlite3
|
261
283
|
requirement: !ruby/object:Gem::Requirement
|
@@ -297,6 +319,7 @@ files:
|
|
297
319
|
- lib/paper_trail/cleaner.rb
|
298
320
|
- lib/paper_trail/compatibility.rb
|
299
321
|
- lib/paper_trail/config.rb
|
322
|
+
- lib/paper_trail/errors.rb
|
300
323
|
- lib/paper_trail/events/base.rb
|
301
324
|
- lib/paper_trail/events/create.rb
|
302
325
|
- lib/paper_trail/events/destroy.rb
|
@@ -311,9 +334,11 @@ files:
|
|
311
334
|
- lib/paper_trail/frameworks/rspec/helpers.rb
|
312
335
|
- lib/paper_trail/has_paper_trail.rb
|
313
336
|
- lib/paper_trail/model_config.rb
|
337
|
+
- lib/paper_trail/queries/versions/where_attribute_changes.rb
|
314
338
|
- lib/paper_trail/queries/versions/where_object.rb
|
315
339
|
- lib/paper_trail/queries/versions/where_object_changes.rb
|
316
340
|
- lib/paper_trail/queries/versions/where_object_changes_from.rb
|
341
|
+
- lib/paper_trail/queries/versions/where_object_changes_to.rb
|
317
342
|
- lib/paper_trail/record_history.rb
|
318
343
|
- lib/paper_trail/record_trail.rb
|
319
344
|
- lib/paper_trail/reifier.rb
|
@@ -335,15 +360,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
335
360
|
requirements:
|
336
361
|
- - ">="
|
337
362
|
- !ruby/object:Gem::Version
|
338
|
-
version: 2.
|
363
|
+
version: 2.6.0
|
339
364
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
340
365
|
requirements:
|
341
366
|
- - ">="
|
342
367
|
- !ruby/object:Gem::Version
|
343
368
|
version: 1.3.6
|
344
369
|
requirements: []
|
345
|
-
|
346
|
-
rubygems_version: 2.7.6.2
|
370
|
+
rubygems_version: 3.2.22
|
347
371
|
signing_key:
|
348
372
|
specification_version: 4
|
349
373
|
summary: Track changes to your models.
|