paper_trail 12.0.0 → 12.1.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/update_item_subtype/update_item_subtype_generator.rb +4 -2
- data/lib/paper_trail/compatibility.rb +1 -1
- data/lib/paper_trail/errors.rb +33 -0
- data/lib/paper_trail/events/base.rb +14 -10
- data/lib/paper_trail/model_config.rb +24 -25
- 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 +1 -1
- 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 +0 -20
- data/lib/paper_trail/version_concern.rb +45 -14
- data/lib/paper_trail/version_number.rb +1 -1
- data/lib/paper_trail.rb +3 -2
- metadata +61 -25
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e29e666977c2b4072eab98684b884cb43dba15e85367eb8221b9294ebad945c
|
4
|
+
data.tar.gz: 750c5670a52675ab4dcc17bfd5389eaf87ebe4d4a3a68ccbb7ed2da1bd43e52f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b44b40b4683d987d67faf3fabb87d603cd6d99dad2c0c3b6b2859c5d30fd862fe3058e2fa1a1cea982a15ec45a4b8b194a55590b8d523aa8630d3b0644374b8e
|
7
|
+
data.tar.gz: '0882176106dfa57ce49b0cf0c1267e2465e134a07719fc3436beec7cad5e10a23c6ff7d409b3332123cf8a5b7ce99e854351e4d60072894026027772f1cc14e8'
|
@@ -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)
|
@@ -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.0" # 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,11 @@ 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
|
-
@changes_in_latest_version ||= begin
|
119
|
-
if @in_after_callback
|
120
|
-
@record.saved_changes
|
121
|
-
else
|
122
|
-
@record.changes
|
123
|
-
end
|
124
|
-
end
|
116
|
+
@changes_in_latest_version ||= load_changes_in_latest_version
|
125
117
|
end
|
126
118
|
|
127
119
|
# An attributed is "ignored" if it is listed in the `:ignore` option
|
@@ -134,6 +126,18 @@ module PaperTrail
|
|
134
126
|
ignored.any? && (changed_in_latest_version & ignored).any?
|
135
127
|
end
|
136
128
|
|
129
|
+
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
130
|
+
# https://github.com/paper-trail-gem/paper_trail/pull/899
|
131
|
+
#
|
132
|
+
# @api private
|
133
|
+
def load_changes_in_latest_version
|
134
|
+
if @in_after_callback
|
135
|
+
@record.saved_changes
|
136
|
+
else
|
137
|
+
@record.changes
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
137
141
|
# PT 10 has a new optional column, `item_subtype`
|
138
142
|
#
|
139
143
|
# @api private
|
@@ -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.
|
@@ -53,13 +48,7 @@ module PaperTrail
|
|
53
48
|
#
|
54
49
|
# @api public
|
55
50
|
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
|
51
|
+
assert_valid_recording_order_for_on_destroy(recording_order)
|
63
52
|
|
64
53
|
@model_class.send(
|
65
54
|
"#{recording_order}_destroy",
|
@@ -97,11 +86,18 @@ module PaperTrail
|
|
97
86
|
end
|
98
87
|
|
99
88
|
# Adds a callback that records a version after a "touch" event.
|
89
|
+
#
|
90
|
+
# Rails < 6.0 has a bug where dirty-tracking does not occur during
|
91
|
+
# a `touch`. (https://github.com/rails/rails/issues/33429) See also:
|
92
|
+
# https://github.com/paper-trail-gem/paper_trail/issues/1121
|
93
|
+
# https://github.com/paper-trail-gem/paper_trail/issues/1161
|
94
|
+
# https://github.com/paper-trail-gem/paper_trail/pull/1285
|
95
|
+
#
|
100
96
|
# @api public
|
101
97
|
def on_touch
|
102
98
|
@model_class.after_touch { |r|
|
103
99
|
r.paper_trail.record_update(
|
104
|
-
force:
|
100
|
+
force: RAILS_LT_6_0,
|
105
101
|
in_after_callback: true,
|
106
102
|
is_touch: true
|
107
103
|
)
|
@@ -117,7 +113,6 @@ module PaperTrail
|
|
117
113
|
@model_class.send :include, ::PaperTrail::Model::InstanceMethods
|
118
114
|
setup_options(options)
|
119
115
|
setup_associations(options)
|
120
|
-
check_presence_of_item_subtype_column(options)
|
121
116
|
@model_class.after_rollback { paper_trail.clear_rolled_back_versions }
|
122
117
|
setup_callbacks_from_options options[:on]
|
123
118
|
end
|
@@ -129,26 +124,30 @@ module PaperTrail
|
|
129
124
|
|
130
125
|
private
|
131
126
|
|
127
|
+
RAILS_LT_6_0 = ::ActiveRecord.gem_version < ::Gem::Version.new("6.0.0")
|
128
|
+
private_constant :RAILS_LT_6_0
|
129
|
+
|
132
130
|
# Raises an error if the provided class is an `abstract_class`.
|
133
131
|
# @api private
|
134
132
|
def assert_concrete_activerecord_class(class_name)
|
135
133
|
if class_name.constantize.abstract_class?
|
136
|
-
raise format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
|
134
|
+
raise Error, format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
|
137
135
|
end
|
138
136
|
end
|
139
137
|
|
140
|
-
|
141
|
-
|
138
|
+
# @api private
|
139
|
+
def assert_valid_recording_order_for_on_destroy(recording_order)
|
140
|
+
unless %w[after before].include?(recording_order.to_s)
|
141
|
+
raise ArgumentError, 'recording order can only be "after" or "before"'
|
142
|
+
end
|
143
|
+
|
144
|
+
if recording_order.to_s == "after" && cannot_record_after_destroy?
|
145
|
+
raise Error, E_CANNOT_RECORD_AFTER_DESTROY
|
146
|
+
end
|
142
147
|
end
|
143
148
|
|
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)
|
149
|
+
def cannot_record_after_destroy?
|
150
|
+
::ActiveRecord::Base.belongs_to_required_by_default
|
152
151
|
end
|
153
152
|
|
154
153
|
def check_version_class_name(options)
|
@@ -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
|
@@ -283,7 +283,7 @@ module PaperTrail
|
|
283
283
|
def log_version_errors(version, action)
|
284
284
|
version.logger&.warn(
|
285
285
|
"Unable to create version for #{action} of #{@record.class.name}" \
|
286
|
-
|
286
|
+
"##{@record.id}: " + version.errors.full_messages.join(", ")
|
287
287
|
)
|
288
288
|
end
|
289
289
|
|
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
|
@@ -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
|
@@ -21,10 +23,6 @@ module PaperTrail
|
|
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,22 @@ 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
|
-
if
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
379
|
+
if limit_option?(item.class)
|
380
|
+
item.class.paper_trail_options[:limit]
|
381
|
+
elsif base_class_limit_option?(item.class)
|
382
|
+
item.class.base_class.paper_trail_options[:limit]
|
383
|
+
else
|
384
|
+
PaperTrail.config.version_limit
|
361
385
|
end
|
362
|
-
|
386
|
+
end
|
387
|
+
|
388
|
+
def limit_option?(klass)
|
389
|
+
klass.respond_to?(:paper_trail_options) && klass.paper_trail_options.key?(:limit)
|
390
|
+
end
|
391
|
+
|
392
|
+
def base_class_limit_option?(klass)
|
393
|
+
klass.respond_to?(:base_class) && limit_option?(klass.base_class)
|
363
394
|
end
|
364
395
|
end
|
365
396
|
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"
|
@@ -68,7 +69,7 @@ module PaperTrail
|
|
68
69
|
#
|
69
70
|
# @api public
|
70
71
|
def request(options = nil, &block)
|
71
|
-
if options.nil? && !
|
72
|
+
if options.nil? && !block
|
72
73
|
Request
|
73
74
|
else
|
74
75
|
Request.with(options, &block)
|
@@ -78,7 +79,7 @@ module PaperTrail
|
|
78
79
|
# Set the field which records when a version was created.
|
79
80
|
# @api public
|
80
81
|
def timestamp_field=(_field_name)
|
81
|
-
raise
|
82
|
+
raise Error, E_TIMESTAMP_FIELD_CONFIG
|
82
83
|
end
|
83
84
|
|
84
85
|
# 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.1.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: 2021-
|
13
|
+
date: 2021-08-30 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -46,14 +46,14 @@ 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
|
@@ -74,14 +74,14 @@ dependencies:
|
|
74
74
|
requirements:
|
75
75
|
- - "~>"
|
76
76
|
- !ruby/object:Gem::Version
|
77
|
-
version:
|
77
|
+
version: 2.19.0
|
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:
|
84
|
+
version: 2.19.0
|
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,84 +144,118 @@ 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.20.0
|
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.20.0
|
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.11.3
|
204
|
+
type: :development
|
205
|
+
prerelease: false
|
206
|
+
version_requirements: !ruby/object:Gem::Requirement
|
207
|
+
requirements:
|
208
|
+
- - "~>"
|
209
|
+
- !ruby/object:Gem::Version
|
210
|
+
version: 2.11.3
|
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.4.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.4.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'
|
246
|
+
- - "<"
|
247
|
+
- !ruby/object:Gem::Version
|
248
|
+
version: '0.22'
|
249
|
+
type: :development
|
250
|
+
prerelease: false
|
251
|
+
version_requirements: !ruby/object:Gem::Requirement
|
252
|
+
requirements:
|
253
|
+
- - ">="
|
254
|
+
- !ruby/object:Gem::Version
|
255
|
+
version: '0.21'
|
256
|
+
- - "<"
|
257
|
+
- !ruby/object:Gem::Version
|
258
|
+
version: '0.22'
|
225
259
|
- !ruby/object:Gem::Dependency
|
226
260
|
name: mysql2
|
227
261
|
requirement: !ruby/object:Gem::Requirement
|
@@ -297,6 +331,7 @@ files:
|
|
297
331
|
- lib/paper_trail/cleaner.rb
|
298
332
|
- lib/paper_trail/compatibility.rb
|
299
333
|
- lib/paper_trail/config.rb
|
334
|
+
- lib/paper_trail/errors.rb
|
300
335
|
- lib/paper_trail/events/base.rb
|
301
336
|
- lib/paper_trail/events/create.rb
|
302
337
|
- lib/paper_trail/events/destroy.rb
|
@@ -311,9 +346,11 @@ files:
|
|
311
346
|
- lib/paper_trail/frameworks/rspec/helpers.rb
|
312
347
|
- lib/paper_trail/has_paper_trail.rb
|
313
348
|
- lib/paper_trail/model_config.rb
|
349
|
+
- lib/paper_trail/queries/versions/where_attribute_changes.rb
|
314
350
|
- lib/paper_trail/queries/versions/where_object.rb
|
315
351
|
- lib/paper_trail/queries/versions/where_object_changes.rb
|
316
352
|
- lib/paper_trail/queries/versions/where_object_changes_from.rb
|
353
|
+
- lib/paper_trail/queries/versions/where_object_changes_to.rb
|
317
354
|
- lib/paper_trail/record_history.rb
|
318
355
|
- lib/paper_trail/record_trail.rb
|
319
356
|
- lib/paper_trail/reifier.rb
|
@@ -342,8 +379,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
342
379
|
- !ruby/object:Gem::Version
|
343
380
|
version: 1.3.6
|
344
381
|
requirements: []
|
345
|
-
|
346
|
-
rubygems_version: 2.7.6.2
|
382
|
+
rubygems_version: 3.2.22
|
347
383
|
signing_key:
|
348
384
|
specification_version: 4
|
349
385
|
summary: Track changes to your models.
|