paper_trail 11.1.0 → 15.2.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 +29 -5
- data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +11 -6
- data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +4 -2
- data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +24 -10
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +10 -10
- data/lib/paper_trail/attribute_serializers/object_attribute.rb +13 -3
- data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +13 -3
- data/lib/paper_trail/compatibility.rb +3 -3
- data/lib/paper_trail/errors.rb +33 -0
- data/lib/paper_trail/events/base.rb +84 -64
- data/lib/paper_trail/events/destroy.rb +1 -1
- data/lib/paper_trail/events/update.rb +23 -7
- data/lib/paper_trail/frameworks/active_record.rb +9 -2
- data/lib/paper_trail/frameworks/rails/controller.rb +0 -6
- data/lib/paper_trail/frameworks/rails/railtie.rb +34 -0
- data/lib/paper_trail/frameworks/rails.rb +1 -2
- data/lib/paper_trail/has_paper_trail.rb +4 -0
- data/lib/paper_trail/model_config.rb +51 -45
- 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 +9 -14
- data/lib/paper_trail/queries/versions/where_object_changes_from.rb +57 -0
- data/lib/paper_trail/queries/versions/where_object_changes_to.rb +57 -0
- data/lib/paper_trail/record_trail.rb +81 -64
- data/lib/paper_trail/reifier.rb +27 -10
- data/lib/paper_trail/request.rb +22 -25
- data/lib/paper_trail/serializers/json.rb +0 -10
- data/lib/paper_trail/serializers/yaml.rb +38 -13
- data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +1 -14
- data/lib/paper_trail/version_concern.rb +74 -22
- data/lib/paper_trail/version_number.rb +2 -2
- data/lib/paper_trail.rb +30 -40
- metadata +98 -45
- data/Gemfile +0 -4
- data/lib/paper_trail/frameworks/rails/engine.rb +0 -45
- data/paper_trail.gemspec +0 -69
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`.
|
@@ -78,28 +75,6 @@ module PaperTrail
|
|
78
75
|
!!store.fetch(:"enabled_for_#{model}", true)
|
79
76
|
end
|
80
77
|
|
81
|
-
# @api private
|
82
|
-
def merge(options)
|
83
|
-
options.to_h.each do |k, v|
|
84
|
-
store[k] = v
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
# @api private
|
89
|
-
def set(options)
|
90
|
-
store.clear
|
91
|
-
merge(options)
|
92
|
-
end
|
93
|
-
|
94
|
-
# Returns a deep copy of the internal hash from our RequestStore. Keys are
|
95
|
-
# all symbols. Values are mostly primitives, but whodunnit can be a Proc.
|
96
|
-
# We cannot use Marshal.dump here because it doesn't support Proc. It is
|
97
|
-
# unclear exactly how `deep_dup` handles a Proc, but it doesn't complain.
|
98
|
-
# @api private
|
99
|
-
def to_h
|
100
|
-
store.deep_dup
|
101
|
-
end
|
102
|
-
|
103
78
|
# Temporarily set `options` and execute a block.
|
104
79
|
# @api private
|
105
80
|
def with(options)
|
@@ -136,6 +111,19 @@ module PaperTrail
|
|
136
111
|
|
137
112
|
private
|
138
113
|
|
114
|
+
# @api private
|
115
|
+
def merge(options)
|
116
|
+
options.to_h.each do |k, v|
|
117
|
+
store[k] = v
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# @api private
|
122
|
+
def set(options)
|
123
|
+
store.clear
|
124
|
+
merge(options)
|
125
|
+
end
|
126
|
+
|
139
127
|
# Returns a Hash, initializing with default values if necessary.
|
140
128
|
# @api private
|
141
129
|
def store
|
@@ -144,6 +132,15 @@ module PaperTrail
|
|
144
132
|
}
|
145
133
|
end
|
146
134
|
|
135
|
+
# Returns a deep copy of the internal hash from our RequestStore. Keys are
|
136
|
+
# all symbols. Values are mostly primitives, but whodunnit can be a Proc.
|
137
|
+
# We cannot use Marshal.dump here because it doesn't support Proc. It is
|
138
|
+
# unclear exactly how `deep_dup` handles a Proc, but it doesn't complain.
|
139
|
+
# @api private
|
140
|
+
def to_h
|
141
|
+
store.deep_dup
|
142
|
+
end
|
143
|
+
|
147
144
|
# Provide a helpful error message if someone has a typo in one of their
|
148
145
|
# option keys. We don't validate option values here. That's traditionally
|
149
146
|
# been handled with casting (`to_s`, `!!`) in the accessor method.
|
@@ -31,16 +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
34
|
end
|
45
35
|
end
|
46
36
|
end
|
@@ -9,13 +9,23 @@ module PaperTrail
|
|
9
9
|
extend self # makes all instance methods become module methods as well
|
10
10
|
|
11
11
|
def load(string)
|
12
|
-
|
12
|
+
if use_safe_load?
|
13
|
+
::YAML.safe_load(
|
14
|
+
string,
|
15
|
+
permitted_classes: yaml_column_permitted_classes,
|
16
|
+
aliases: true
|
17
|
+
)
|
18
|
+
elsif ::YAML.respond_to?(:unsafe_load)
|
19
|
+
::YAML.unsafe_load(string)
|
20
|
+
else
|
21
|
+
::YAML.load(string)
|
22
|
+
end
|
13
23
|
end
|
14
24
|
|
15
25
|
# @param object (Hash | HashWithIndifferentAccess) - Coming from
|
16
26
|
# `recordable_object` `object` will be a plain `Hash`. However, due to
|
17
|
-
# recent [memory optimizations](https://
|
18
|
-
# `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
|
27
|
+
# recent [memory optimizations](https://github.com/paper-trail-gem/paper_trail/pull/1189),
|
28
|
+
# when coming from `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
|
19
29
|
def dump(object)
|
20
30
|
object = object.to_hash if object.is_a?(HashWithIndifferentAccess)
|
21
31
|
::YAML.dump object
|
@@ -27,16 +37,31 @@ module PaperTrail
|
|
27
37
|
arel_field.matches("%\n#{field}: #{value}\n%")
|
28
38
|
end
|
29
39
|
|
30
|
-
|
31
|
-
|
32
|
-
def
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
+
private
|
41
|
+
|
42
|
+
def use_safe_load?
|
43
|
+
if ::ActiveRecord.gem_version >= Gem::Version.new("7.0.3.1")
|
44
|
+
# `use_yaml_unsafe_load` may be removed in the future, at which point
|
45
|
+
# safe loading will be the default.
|
46
|
+
!defined?(ActiveRecord.use_yaml_unsafe_load) || !ActiveRecord.use_yaml_unsafe_load
|
47
|
+
elsif defined?(ActiveRecord::Base.use_yaml_unsafe_load)
|
48
|
+
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
|
49
|
+
!ActiveRecord::Base.use_yaml_unsafe_load
|
50
|
+
else
|
51
|
+
false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def yaml_column_permitted_classes
|
56
|
+
if defined?(ActiveRecord.yaml_column_permitted_classes)
|
57
|
+
# Rails >= 7.0.3.1
|
58
|
+
ActiveRecord.yaml_column_permitted_classes
|
59
|
+
elsif defined?(ActiveRecord::Base.yaml_column_permitted_classes)
|
60
|
+
# Rails 5.2.8.1, 6.0.5.1, 6.1.6.1
|
61
|
+
ActiveRecord::Base.yaml_column_permitted_classes
|
62
|
+
else
|
63
|
+
[]
|
64
|
+
end
|
40
65
|
end
|
41
66
|
end
|
42
67
|
end
|
@@ -11,15 +11,12 @@ module PaperTrail
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def serialize(array)
|
14
|
-
return serialize_with_ar(array) if active_record_pre_502?
|
15
14
|
array
|
16
15
|
end
|
17
16
|
|
18
17
|
def deserialize(array)
|
19
|
-
return deserialize_with_ar(array) if active_record_pre_502?
|
20
|
-
|
21
18
|
case array
|
22
|
-
# Needed for legacy
|
19
|
+
# Needed for legacy data. If serialized array is a string
|
23
20
|
# then it was serialized with Rails < 5.0.2.
|
24
21
|
when ::String then deserialize_with_ar(array)
|
25
22
|
else array
|
@@ -28,16 +25,6 @@ module PaperTrail
|
|
28
25
|
|
29
26
|
private
|
30
27
|
|
31
|
-
def active_record_pre_502?
|
32
|
-
::ActiveRecord.gem_version < Gem::Version.new("5.0.2")
|
33
|
-
end
|
34
|
-
|
35
|
-
def serialize_with_ar(array)
|
36
|
-
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.
|
37
|
-
new(@subtype, @delimiter).
|
38
|
-
serialize(array)
|
39
|
-
end
|
40
|
-
|
41
28
|
def deserialize_with_ar(array)
|
42
29
|
ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.
|
43
30
|
new(@subtype, @delimiter).
|
@@ -1,8 +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"
|
7
|
+
require "paper_trail/queries/versions/where_object_changes_from"
|
8
|
+
require "paper_trail/queries/versions/where_object_changes_to"
|
6
9
|
|
7
10
|
module PaperTrail
|
8
11
|
# Originally, PaperTrail did not provide this module, and all of this
|
@@ -12,23 +15,20 @@ module PaperTrail
|
|
12
15
|
module VersionConcern
|
13
16
|
extend ::ActiveSupport::Concern
|
14
17
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
end
|
18
|
+
E_YAML_PERMITTED_CLASSES = <<-EOS.squish.freeze
|
19
|
+
PaperTrail encountered a Psych::DisallowedClass error during
|
20
|
+
deserialization of YAML column, indicating that
|
21
|
+
yaml_column_permitted_classes has not been configured correctly. %s
|
22
|
+
EOS
|
21
23
|
|
24
|
+
included do
|
25
|
+
belongs_to :item, polymorphic: true, optional: true, inverse_of: false
|
22
26
|
validates_presence_of :event
|
23
27
|
after_create :enforce_version_limit!
|
24
28
|
end
|
25
29
|
|
26
30
|
# :nodoc:
|
27
31
|
module ClassMethods
|
28
|
-
def item_subtype_column_present?
|
29
|
-
column_names.include?("item_subtype")
|
30
|
-
end
|
31
|
-
|
32
32
|
def with_item_keys(item_type, item_id)
|
33
33
|
where item_type: item_type, item_id: item_id
|
34
34
|
end
|
@@ -46,7 +46,7 @@ module PaperTrail
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def not_creates
|
49
|
-
where
|
49
|
+
where.not(event: "create")
|
50
50
|
end
|
51
51
|
|
52
52
|
def between(start_time, end_time)
|
@@ -64,6 +64,18 @@ module PaperTrail
|
|
64
64
|
end
|
65
65
|
end
|
66
66
|
|
67
|
+
# Given an attribute like `"name"`, query the `versions.object_changes`
|
68
|
+
# column for any changes that modified the provided attribute.
|
69
|
+
#
|
70
|
+
# @api public
|
71
|
+
def where_attribute_changes(attribute)
|
72
|
+
unless attribute.is_a?(String) || attribute.is_a?(Symbol)
|
73
|
+
raise ArgumentError, "expected to receive a String or Symbol"
|
74
|
+
end
|
75
|
+
|
76
|
+
Queries::Versions::WhereAttributeChanges.new(self, attribute).execute
|
77
|
+
end
|
78
|
+
|
67
79
|
# Given a hash of attributes like `name: 'Joan'`, query the
|
68
80
|
# `versions.objects` column.
|
69
81
|
#
|
@@ -120,6 +132,36 @@ module PaperTrail
|
|
120
132
|
Queries::Versions::WhereObjectChanges.new(self, args).execute
|
121
133
|
end
|
122
134
|
|
135
|
+
# Given a hash of attributes like `name: 'Joan'`, query the
|
136
|
+
# `versions.objects_changes` column for changes where the version changed
|
137
|
+
# from the hash of attributes to other values.
|
138
|
+
#
|
139
|
+
# This is useful for finding versions where the attribute started with a
|
140
|
+
# known value and changed to something else. This is in comparison to
|
141
|
+
# `where_object_changes` which will find both the changes before and
|
142
|
+
# after.
|
143
|
+
#
|
144
|
+
# @api public
|
145
|
+
def where_object_changes_from(args = {})
|
146
|
+
raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
|
147
|
+
Queries::Versions::WhereObjectChangesFrom.new(self, args).execute
|
148
|
+
end
|
149
|
+
|
150
|
+
# Given a hash of attributes like `name: 'Joan'`, query the
|
151
|
+
# `versions.objects_changes` column for changes where the version changed
|
152
|
+
# to the hash of attributes from other values.
|
153
|
+
#
|
154
|
+
# This is useful for finding versions where the attribute started with an
|
155
|
+
# unknown value and changed to a known value. This is in comparison to
|
156
|
+
# `where_object_changes` which will find both the changes before and
|
157
|
+
# after.
|
158
|
+
#
|
159
|
+
# @api public
|
160
|
+
def where_object_changes_to(args = {})
|
161
|
+
raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
|
162
|
+
Queries::Versions::WhereObjectChangesTo.new(self, args).execute
|
163
|
+
end
|
164
|
+
|
123
165
|
def primary_key_is_int?
|
124
166
|
@primary_key_is_int ||= columns_hash[primary_key].type == :integer
|
125
167
|
rescue StandardError # TODO: Rescue something more specific
|
@@ -226,7 +268,7 @@ module PaperTrail
|
|
226
268
|
#
|
227
269
|
def reify(options = {})
|
228
270
|
unless self.class.column_names.include? "object"
|
229
|
-
raise "reify
|
271
|
+
raise Error, "reify requires an object column"
|
230
272
|
end
|
231
273
|
return nil if object.nil?
|
232
274
|
::PaperTrail::Reifier.reify(self, options)
|
@@ -273,7 +315,7 @@ module PaperTrail
|
|
273
315
|
|
274
316
|
# @api private
|
275
317
|
def load_changeset
|
276
|
-
if PaperTrail.config.object_changes_adapter
|
318
|
+
if PaperTrail.config.object_changes_adapter.respond_to?(:load_changeset)
|
277
319
|
return PaperTrail.config.object_changes_adapter.load_changeset(self)
|
278
320
|
end
|
279
321
|
|
@@ -312,7 +354,10 @@ module PaperTrail
|
|
312
354
|
else
|
313
355
|
begin
|
314
356
|
PaperTrail.serializer.load(object_changes)
|
315
|
-
rescue StandardError
|
357
|
+
rescue StandardError => e
|
358
|
+
if defined?(::Psych::Exception) && e.instance_of?(::Psych::Exception)
|
359
|
+
::Kernel.warn format(E_YAML_PERMITTED_CLASSES, e)
|
360
|
+
end
|
316
361
|
{}
|
317
362
|
end
|
318
363
|
end
|
@@ -339,16 +384,23 @@ module PaperTrail
|
|
339
384
|
# The version limit can be global or per-model.
|
340
385
|
#
|
341
386
|
# @api private
|
342
|
-
#
|
343
|
-
# TODO: Duplication: similar `constantize` in Reifier#version_reification_class
|
344
387
|
def version_limit
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
388
|
+
klass = item.class
|
389
|
+
if limit_option?(klass)
|
390
|
+
klass.paper_trail_options[:limit]
|
391
|
+
elsif base_class_limit_option?(klass)
|
392
|
+
klass.base_class.paper_trail_options[:limit]
|
393
|
+
else
|
394
|
+
PaperTrail.config.version_limit
|
350
395
|
end
|
351
|
-
|
396
|
+
end
|
397
|
+
|
398
|
+
def limit_option?(klass)
|
399
|
+
klass.respond_to?(:paper_trail_options) && klass.paper_trail_options.key?(:limit)
|
400
|
+
end
|
401
|
+
|
402
|
+
def base_class_limit_option?(klass)
|
403
|
+
klass.respond_to?(:base_class) && limit_option?(klass.base_class)
|
352
404
|
end
|
353
405
|
end
|
354
406
|
end
|
@@ -7,8 +7,8 @@ module PaperTrail
|
|
7
7
|
# because of this confusion, but it's not worth the breaking change.
|
8
8
|
# People are encouraged to use `PaperTrail.gem_version` instead.
|
9
9
|
module VERSION
|
10
|
-
MAJOR =
|
11
|
-
MINOR =
|
10
|
+
MAJOR = 15
|
11
|
+
MINOR = 2
|
12
12
|
TINY = 0
|
13
13
|
|
14
14
|
# Set PRE to nil unless it's a pre-release (beta, rc, etc.)
|
data/lib/paper_trail.rb
CHANGED
@@ -8,34 +8,24 @@
|
|
8
8
|
# can revisit this decision.
|
9
9
|
require "active_support/all"
|
10
10
|
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
|
11
|
+
# We used to `require "active_record"` here, but that was [replaced with a
|
12
|
+
# Railtie](https://github.com/paper-trail-gem/paper_trail/pull/1281) in PT 12.
|
13
|
+
# As a result, we cannot reference `ActiveRecord` in this file (ie. until our
|
14
|
+
# Railtie has loaded). If we did, it would cause [problems with non-Rails
|
15
|
+
# projects](https://github.com/paper-trail-gem/paper_trail/pull/1401).
|
16
16
|
|
17
|
-
require "
|
17
|
+
require "paper_trail/errors"
|
18
18
|
require "paper_trail/cleaner"
|
19
19
|
require "paper_trail/compatibility"
|
20
20
|
require "paper_trail/config"
|
21
|
-
require "paper_trail/has_paper_trail"
|
22
21
|
require "paper_trail/record_history"
|
23
|
-
require "paper_trail/reifier"
|
24
22
|
require "paper_trail/request"
|
25
|
-
require "paper_trail/version_concern"
|
26
23
|
require "paper_trail/version_number"
|
27
24
|
require "paper_trail/serializers/json"
|
28
|
-
require "paper_trail/serializers/yaml"
|
29
25
|
|
30
26
|
# An ActiveRecord extension that tracks changes to your models, for auditing or
|
31
27
|
# versioning.
|
32
28
|
module PaperTrail
|
33
|
-
E_RAILS_NOT_LOADED = <<-EOS.squish.freeze
|
34
|
-
PaperTrail has been loaded too early, before rails is loaded. This can
|
35
|
-
happen when another gem defines the ::Rails namespace, then PT is loaded,
|
36
|
-
all before rails is loaded. You may want to reorder your Gemfile, or defer
|
37
|
-
the loading of PT by using `require: false` and a manual require elsewhere.
|
38
|
-
EOS
|
39
29
|
E_TIMESTAMP_FIELD_CONFIG = <<-EOS.squish.freeze
|
40
30
|
PaperTrail.timestamp_field= has been removed, without replacement. It is no
|
41
31
|
longer configurable. The timestamp column in the versions table must now be
|
@@ -85,7 +75,7 @@ module PaperTrail
|
|
85
75
|
#
|
86
76
|
# @api public
|
87
77
|
def request(options = nil, &block)
|
88
|
-
if options.nil? && !
|
78
|
+
if options.nil? && !block
|
89
79
|
Request
|
90
80
|
else
|
91
81
|
Request.with(options, &block)
|
@@ -95,7 +85,7 @@ module PaperTrail
|
|
95
85
|
# Set the field which records when a version was created.
|
96
86
|
# @api public
|
97
87
|
def timestamp_field=(_field_name)
|
98
|
-
raise
|
88
|
+
raise Error, E_TIMESTAMP_FIELD_CONFIG
|
99
89
|
end
|
100
90
|
|
101
91
|
# Set the PaperTrail serializer. This setting affects all threads.
|
@@ -112,7 +102,7 @@ module PaperTrail
|
|
112
102
|
|
113
103
|
# Returns PaperTrail's global configuration object, a singleton. These
|
114
104
|
# settings affect all threads.
|
115
|
-
# @api
|
105
|
+
# @api public
|
116
106
|
def config
|
117
107
|
@config ||= PaperTrail::Config.instance
|
118
108
|
yield @config if block_given?
|
@@ -120,33 +110,33 @@ module PaperTrail
|
|
120
110
|
end
|
121
111
|
alias configure config
|
122
112
|
|
113
|
+
# @api public
|
123
114
|
def version
|
124
115
|
VERSION::STRING
|
125
116
|
end
|
126
|
-
end
|
127
|
-
end
|
128
117
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
# to learn more about `on_load`.
|
133
|
-
ActiveSupport.on_load(:active_record) do
|
134
|
-
include PaperTrail::Model
|
135
|
-
end
|
118
|
+
def active_record_gte_7_0?
|
119
|
+
@active_record_gte_7_0 ||= ::ActiveRecord.gem_version >= ::Gem::Version.new("7.0.0")
|
120
|
+
end
|
136
121
|
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
# so we check for presence of Rails.application.
|
141
|
-
if defined?(::Rails.application)
|
142
|
-
require "paper_trail/frameworks/rails"
|
143
|
-
else
|
144
|
-
::Kernel.warn(::PaperTrail::E_RAILS_NOT_LOADED)
|
122
|
+
def deprecator
|
123
|
+
@deprecator ||= ActiveSupport::Deprecation.new("16.0", "PaperTrail")
|
124
|
+
end
|
145
125
|
end
|
146
|
-
else
|
147
|
-
require "paper_trail/frameworks/active_record"
|
148
126
|
end
|
149
127
|
|
150
|
-
|
151
|
-
|
128
|
+
# PT is built on ActiveRecord, but does not require Rails. If Rails is defined,
|
129
|
+
# our Railtie makes sure not to load the AR-dependent parts of PT until AR is
|
130
|
+
# ready. A typical Rails `application.rb` has:
|
131
|
+
#
|
132
|
+
# ```
|
133
|
+
# require 'rails/all' # Defines `Rails`
|
134
|
+
# Bundler.require(*Rails.groups) # require 'paper_trail' (this file)
|
135
|
+
# ```
|
136
|
+
#
|
137
|
+
# Non-rails applications should take similar care to load AR before PT.
|
138
|
+
if defined?(Rails)
|
139
|
+
require "paper_trail/frameworks/rails"
|
140
|
+
else
|
141
|
+
require "paper_trail/frameworks/active_record"
|
152
142
|
end
|