paper_trail 10.2.1 → 11.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/generators/paper_trail/install/install_generator.rb +7 -3
- data/lib/generators/paper_trail/install/templates/create_versions.rb.erb +1 -1
- data/lib/generators/paper_trail/migration_generator.rb +5 -4
- data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +10 -42
- data/lib/paper_trail/compatibility.rb +51 -0
- data/lib/paper_trail/config.rb +0 -33
- data/lib/paper_trail/events/base.rb +10 -7
- data/lib/paper_trail/frameworks/rails/controller.rb +1 -3
- data/lib/paper_trail/model_config.rb +17 -6
- data/lib/paper_trail/reifier.rb +18 -19
- data/lib/paper_trail/version_concern.rb +33 -20
- data/lib/paper_trail/version_number.rb +3 -3
- data/lib/paper_trail.rb +5 -0
- metadata +43 -43
- data/lib/generators/paper_trail/install_generator.rb +0 -99
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f8f7237a39b0645932b394ee0332846be680f6a725ed02c7a126aa892d840ccc
|
4
|
+
data.tar.gz: b0356d622a6e6f3ba0938c4d9fe0ff211b347a0c65e2d3a6574bc8bf5fb04df6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 46ad3d73231d4ab6c3d978925e7b838af2697b2b998b9a7948d078266fbdbec33b6dbdcbfb93751f2aa961be6a3499f499a71d56e3fbc6138174cb752feae41a
|
7
|
+
data.tar.gz: 9ec2fc044229898aa2c5ab70dc41b549b6896c61af42633af0760e6b99aadd375f5f7e39160ad713131ecb439b0f5aff8cb6696f276f4c5225eb40e371f43035
|
@@ -25,10 +25,14 @@ module PaperTrail
|
|
25
25
|
" See section 5.c. Generators in README.md for more information."
|
26
26
|
|
27
27
|
def create_migration_file
|
28
|
-
add_paper_trail_migration(
|
28
|
+
add_paper_trail_migration(
|
29
|
+
"create_versions",
|
29
30
|
item_type_options: item_type_options,
|
30
|
-
versions_table_options: versions_table_options
|
31
|
-
|
31
|
+
versions_table_options: versions_table_options
|
32
|
+
)
|
33
|
+
if options.with_changes?
|
34
|
+
add_paper_trail_migration("add_object_changes_to_versions")
|
35
|
+
end
|
32
36
|
end
|
33
37
|
|
34
38
|
private
|
@@ -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.bigint :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,10 +28,11 @@ module PaperTrail
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def migration_version
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
format(
|
32
|
+
"[%d.%d]",
|
33
|
+
ActiveRecord::VERSION::MAJOR,
|
34
|
+
ActiveRecord::VERSION::MINOR
|
35
|
+
)
|
35
36
|
end
|
36
37
|
end
|
37
38
|
end
|
@@ -32,50 +32,18 @@ module PaperTrail
|
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
AttributeSerializerFactory.for(@klass, attr).serialize(val)
|
40
|
-
end
|
41
|
-
|
42
|
-
def deserialize(attr, val)
|
43
|
-
if defined_enums[attr] && val.is_a?(::String)
|
44
|
-
# Because PT 4 used to save the string version of enums to `object_changes`
|
45
|
-
val
|
46
|
-
else
|
47
|
-
AttributeSerializerFactory.for(@klass, attr).deserialize(val)
|
48
|
-
end
|
49
|
-
end
|
35
|
+
# Uses AR 5's `serialize` and `deserialize`.
|
36
|
+
class CastAttributeSerializer
|
37
|
+
def serialize(attr, val)
|
38
|
+
AttributeSerializerFactory.for(@klass, attr).serialize(val)
|
50
39
|
end
|
51
|
-
else
|
52
|
-
# This implementation uses AR 4.2's `type_cast_for_database`. For
|
53
|
-
# versions of AR < 4.2 we provide an implementation of
|
54
|
-
# `type_cast_for_database` in our shim attribute type classes,
|
55
|
-
# `NoOpAttribute` and `SerializedAttribute`.
|
56
|
-
class CastAttributeSerializer
|
57
|
-
def serialize(attr, val)
|
58
|
-
castable_val = val
|
59
|
-
if defined_enums[attr]
|
60
|
-
# `attr` is an enum. Find the number that corresponds to `val`. If `val` is
|
61
|
-
# a number already, there won't be a corresponding entry, just use `val`.
|
62
|
-
castable_val = defined_enums[attr][val] || val
|
63
|
-
end
|
64
|
-
@klass.type_for_attribute(attr).type_cast_for_database(castable_val)
|
65
|
-
end
|
66
40
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
if defined_enums[attr]
|
74
|
-
defined_enums[attr].key(val)
|
75
|
-
else
|
76
|
-
val
|
77
|
-
end
|
78
|
-
end
|
41
|
+
def deserialize(attr, val)
|
42
|
+
if defined_enums[attr] && val.is_a?(::String)
|
43
|
+
# Because PT 4 used to save the string version of enums to `object_changes`
|
44
|
+
val
|
45
|
+
else
|
46
|
+
AttributeSerializerFactory.for(@klass, attr).deserialize(val)
|
79
47
|
end
|
80
48
|
end
|
81
49
|
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PaperTrail
|
4
|
+
# Rails does not follow SemVer, makes breaking changes in minor versions.
|
5
|
+
# Breaking changes are expected, and are generally good for the rails
|
6
|
+
# ecosystem. However, they often require dozens of hours to fix, even with the
|
7
|
+
# [help of experts](https://github.com/paper-trail-gem/paper_trail/pull/899).
|
8
|
+
#
|
9
|
+
# It is not safe to assume that a new version of rails will be compatible with
|
10
|
+
# PaperTrail. PT is only compatible with the versions of rails that it is
|
11
|
+
# tested against. See `.travis.yml`.
|
12
|
+
#
|
13
|
+
# However, as of
|
14
|
+
# [#1213](https://github.com/paper-trail-gem/paper_trail/pull/1213) our
|
15
|
+
# gemspec allows installation with newer, incompatible rails versions. We hope
|
16
|
+
# this will make it easier for contributors to work on compatibility with
|
17
|
+
# newer rails versions. Most PT users should avoid incompatible rails
|
18
|
+
# versions.
|
19
|
+
module Compatibility
|
20
|
+
ACTIVERECORD_GTE = ">= 5.2" # enforced in gemspec
|
21
|
+
ACTIVERECORD_LT = "< 6.1" # not enforced in gemspec
|
22
|
+
|
23
|
+
E_INCOMPATIBLE_AR = <<-EOS
|
24
|
+
PaperTrail %s is not compatible with ActiveRecord %s. We allow PT
|
25
|
+
contributors to install incompatible versions of ActiveRecord, and this
|
26
|
+
warning can be silenced with an environment variable, but this is a bad
|
27
|
+
idea for normal use. Please install a compatible version of ActiveRecord
|
28
|
+
instead (%s). Please see the discussion in paper_trail/compatibility.rb
|
29
|
+
for details.
|
30
|
+
EOS
|
31
|
+
|
32
|
+
# Normal users need a warning if they accidentally install an incompatible
|
33
|
+
# version of ActiveRecord. Contributors can silence this warning with an
|
34
|
+
# environment variable.
|
35
|
+
def self.check_activerecord(ar_version)
|
36
|
+
raise ::TypeError unless ar_version.instance_of?(::Gem::Version)
|
37
|
+
return if ::ENV["PT_SILENCE_AR_COMPAT_WARNING"].present?
|
38
|
+
req = ::Gem::Requirement.new([ACTIVERECORD_GTE, ACTIVERECORD_LT])
|
39
|
+
unless req.satisfied_by?(ar_version)
|
40
|
+
::Kernel.warn(
|
41
|
+
format(
|
42
|
+
E_INCOMPATIBLE_AR,
|
43
|
+
::PaperTrail.gem_version,
|
44
|
+
ar_version,
|
45
|
+
req
|
46
|
+
)
|
47
|
+
)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/paper_trail/config.rb
CHANGED
@@ -9,14 +9,6 @@ module PaperTrail
|
|
9
9
|
class Config
|
10
10
|
include Singleton
|
11
11
|
|
12
|
-
E_PT_AT_REMOVED = <<-EOS.squish
|
13
|
-
Association Tracking for PaperTrail has been extracted to a separate gem.
|
14
|
-
To use it, please add `paper_trail-association_tracking` to your Gemfile.
|
15
|
-
If you don't use it (most people don't, that's the default) and you set
|
16
|
-
`track_associations = false` somewhere (probably a rails initializer) you
|
17
|
-
can remove that line now.
|
18
|
-
EOS
|
19
|
-
|
20
12
|
attr_accessor(
|
21
13
|
:association_reify_error_behaviour,
|
22
14
|
:object_changes_adapter,
|
@@ -43,30 +35,5 @@ module PaperTrail
|
|
43
35
|
def enabled=(enable)
|
44
36
|
@mutex.synchronize { @enabled = enable }
|
45
37
|
end
|
46
|
-
|
47
|
-
# In PT 10, the paper_trail-association_tracking gem was changed from a
|
48
|
-
# runtime dependency to a development dependency. We raise an error about
|
49
|
-
# this for the people who don't read changelogs.
|
50
|
-
#
|
51
|
-
# We raise a generic RuntimeError instead of a specific PT error class
|
52
|
-
# because there is no known use case where someone would want to rescue
|
53
|
-
# this. If we think of such a use case in the future we can revisit this
|
54
|
-
# decision.
|
55
|
-
#
|
56
|
-
# @override If PT-AT is `require`d, it will replace this method with its
|
57
|
-
# own implementation.
|
58
|
-
def track_associations=(value)
|
59
|
-
if value
|
60
|
-
raise E_PT_AT_REMOVED
|
61
|
-
else
|
62
|
-
::Kernel.warn(E_PT_AT_REMOVED)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
# @override If PT-AT is `require`d, it will replace this method with its
|
67
|
-
# own implementation.
|
68
|
-
def track_associations?
|
69
|
-
raise E_PT_AT_REMOVED
|
70
|
-
end
|
71
38
|
end
|
72
39
|
end
|
@@ -73,14 +73,14 @@ module PaperTrail
|
|
73
73
|
|
74
74
|
# Rails 5.1 changed the API of `ActiveRecord::Dirty`.
|
75
75
|
# @api private
|
76
|
-
def cache_changed_attributes
|
76
|
+
def cache_changed_attributes(&block)
|
77
77
|
if RAILS_GTE_5_1
|
78
78
|
# Everything works fine as it is
|
79
79
|
yield
|
80
80
|
else
|
81
81
|
# Any particular call to `changed_attributes` produces the huge memory allocation.
|
82
82
|
# Lets use the generic AR workaround for that.
|
83
|
-
@record.send(:cache_changed_attributes)
|
83
|
+
@record.send(:cache_changed_attributes, &block)
|
84
84
|
end
|
85
85
|
end
|
86
86
|
|
@@ -107,7 +107,7 @@ module PaperTrail
|
|
107
107
|
end
|
108
108
|
|
109
109
|
# @api private
|
110
|
-
def
|
110
|
+
def calculated_ignored_array
|
111
111
|
ignore = @record.paper_trail_options[:ignore].dup
|
112
112
|
# Remove Hash arguments and then evaluate whether the attributes (the
|
113
113
|
# keys of the hash) should also get pushed into the collection.
|
@@ -117,8 +117,12 @@ module PaperTrail
|
|
117
117
|
ignore << attr if condition.respond_to?(:call) && condition.call(@record)
|
118
118
|
}
|
119
119
|
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# @api private
|
123
|
+
def changed_and_not_ignored
|
120
124
|
skip = @record.paper_trail_options[:skip]
|
121
|
-
(changed_in_latest_version -
|
125
|
+
(changed_in_latest_version - calculated_ignored_array) - skip
|
122
126
|
end
|
123
127
|
|
124
128
|
# @api private
|
@@ -148,7 +152,7 @@ module PaperTrail
|
|
148
152
|
#
|
149
153
|
# @api private
|
150
154
|
def ignored_attr_has_changed?
|
151
|
-
ignored =
|
155
|
+
ignored = calculated_ignored_array + @record.paper_trail_options[:skip]
|
152
156
|
ignored.any? && (changed_in_latest_version & ignored).any?
|
153
157
|
end
|
154
158
|
|
@@ -247,8 +251,7 @@ module PaperTrail
|
|
247
251
|
# @api private
|
248
252
|
def prepare_object_changes(changes)
|
249
253
|
changes = serialize_object_changes(changes)
|
250
|
-
|
251
|
-
changes
|
254
|
+
recordable_object_changes(changes)
|
252
255
|
end
|
253
256
|
|
254
257
|
# Returns an object which can be assigned to the `object_changes`
|
@@ -25,9 +25,7 @@ module PaperTrail
|
|
25
25
|
# @api public
|
26
26
|
def user_for_paper_trail
|
27
27
|
return unless defined?(current_user)
|
28
|
-
|
29
|
-
rescue NoMethodError
|
30
|
-
current_user
|
28
|
+
current_user.try(:id) || current_user
|
31
29
|
end
|
32
30
|
|
33
31
|
# Returns any information about the controller or request that you
|
@@ -18,6 +18,11 @@ 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
|
21
26
|
DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION = <<~STR.squish
|
22
27
|
Passing versions association name as `has_paper_trail versions: %{versions_name}`
|
23
28
|
is deprecated. Use `has_paper_trail versions: {name: %{versions_name}}` instead.
|
@@ -112,6 +117,7 @@ module PaperTrail
|
|
112
117
|
@model_class.send :include, ::PaperTrail::Model::InstanceMethods
|
113
118
|
setup_options(options)
|
114
119
|
setup_associations(options)
|
120
|
+
check_presence_of_item_subtype_column(options)
|
115
121
|
@model_class.after_rollback { paper_trail.clear_rolled_back_versions }
|
116
122
|
setup_callbacks_from_options options[:on]
|
117
123
|
end
|
@@ -122,10 +128,6 @@ module PaperTrail
|
|
122
128
|
|
123
129
|
private
|
124
130
|
|
125
|
-
def active_record_gem_version
|
126
|
-
Gem::Version.new(ActiveRecord::VERSION::STRING)
|
127
|
-
end
|
128
|
-
|
129
131
|
# Raises an error if the provided class is an `abstract_class`.
|
130
132
|
# @api private
|
131
133
|
def assert_concrete_activerecord_class(class_name)
|
@@ -135,8 +137,17 @@ module PaperTrail
|
|
135
137
|
end
|
136
138
|
|
137
139
|
def cannot_record_after_destroy?
|
138
|
-
|
139
|
-
|
140
|
+
::ActiveRecord::Base.belongs_to_required_by_default
|
141
|
+
end
|
142
|
+
|
143
|
+
# Some options require the presence of the `item_subtype` column. Currently
|
144
|
+
# only `limit`, but in the future there may be others.
|
145
|
+
#
|
146
|
+
# @api private
|
147
|
+
def check_presence_of_item_subtype_column(options)
|
148
|
+
return unless options.key?(:limit)
|
149
|
+
return if version_class.item_subtype_column_present?
|
150
|
+
raise format(E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE, @model_class.name)
|
140
151
|
end
|
141
152
|
|
142
153
|
def check_version_class_name(options)
|
data/lib/paper_trail/reifier.rb
CHANGED
@@ -52,23 +52,23 @@ module PaperTrail
|
|
52
52
|
# not the actual subclass. If `type` is present but empty, the class is
|
53
53
|
# the base class.
|
54
54
|
def init_model(attrs, options, version)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
55
|
+
klass = version_reification_class(version, attrs)
|
56
|
+
|
57
|
+
# The `dup` option and destroyed version always returns a new object,
|
58
|
+
# otherwise we should attempt to load item or to look for the item
|
59
|
+
# outside of default scope(s).
|
60
|
+
model = if options[:dup] == true || version.event == "destroy"
|
61
|
+
klass.new
|
62
|
+
else
|
63
|
+
find_cond = { klass.primary_key => version.item_id }
|
64
|
+
|
65
|
+
version.item || klass.unscoped.where(find_cond).first || klass.new
|
66
|
+
end
|
67
|
+
|
68
|
+
if options[:unversioned_attributes] == :nil && !model.new_record?
|
69
|
+
init_unversioned_attrs(attrs, model)
|
71
70
|
end
|
71
|
+
|
72
72
|
model
|
73
73
|
end
|
74
74
|
|
@@ -88,9 +88,7 @@ module PaperTrail
|
|
88
88
|
#
|
89
89
|
# @api private
|
90
90
|
def reify_attribute(k, v, model, version)
|
91
|
-
|
92
|
-
is_enum_without_type_caster = ::ActiveRecord::VERSION::MAJOR < 5 && enums.key?(k)
|
93
|
-
if model.has_attribute?(k) && !is_enum_without_type_caster
|
91
|
+
if model.has_attribute?(k)
|
94
92
|
model[k.to_sym] = v
|
95
93
|
elsif model.respond_to?("#{k}=")
|
96
94
|
model.send("#{k}=", v)
|
@@ -120,6 +118,7 @@ module PaperTrail
|
|
120
118
|
# this method returns the constant `Animal`. You can see this particular
|
121
119
|
# example in action in `spec/models/animal_spec.rb`.
|
122
120
|
#
|
121
|
+
# TODO: Duplication: similar `constantize` in VersionConcern#version_limit
|
123
122
|
def version_reification_class(version, attrs)
|
124
123
|
inheritance_column_name = version.item_type.constantize.inheritance_column
|
125
124
|
inher_col_value = attrs[inheritance_column_name]
|
@@ -25,6 +25,10 @@ module PaperTrail
|
|
25
25
|
|
26
26
|
# :nodoc:
|
27
27
|
module ClassMethods
|
28
|
+
def item_subtype_column_present?
|
29
|
+
column_names.include?("item_subtype")
|
30
|
+
end
|
31
|
+
|
28
32
|
def with_item_keys(item_type, item_id)
|
29
33
|
where item_type: item_type, item_id: item_id
|
30
34
|
end
|
@@ -141,6 +145,7 @@ module PaperTrail
|
|
141
145
|
# Default: false.
|
142
146
|
# @return `ActiveRecord::Relation`
|
143
147
|
# @api public
|
148
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
144
149
|
def preceding(obj, timestamp_arg = false)
|
145
150
|
if timestamp_arg != true && primary_key_is_int?
|
146
151
|
preceding_by_id(obj)
|
@@ -148,6 +153,7 @@ module PaperTrail
|
|
148
153
|
preceding_by_timestamp(obj)
|
149
154
|
end
|
150
155
|
end
|
156
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
151
157
|
|
152
158
|
# Returns versions after `obj`.
|
153
159
|
#
|
@@ -156,6 +162,7 @@ module PaperTrail
|
|
156
162
|
# Default: false.
|
157
163
|
# @return `ActiveRecord::Relation`
|
158
164
|
# @api public
|
165
|
+
# rubocop:disable Style/OptionalBooleanParameter
|
159
166
|
def subsequent(obj, timestamp_arg = false)
|
160
167
|
if timestamp_arg != true && primary_key_is_int?
|
161
168
|
subsequent_by_id(obj)
|
@@ -163,6 +170,7 @@ module PaperTrail
|
|
163
170
|
subsequent_by_timestamp(obj)
|
164
171
|
end
|
165
172
|
end
|
173
|
+
# rubocop:enable Style/OptionalBooleanParameter
|
166
174
|
|
167
175
|
private
|
168
176
|
|
@@ -201,18 +209,8 @@ module PaperTrail
|
|
201
209
|
|
202
210
|
# Restore the item from this version.
|
203
211
|
#
|
204
|
-
# Optionally this can also restore all :has_one and :has_many (including
|
205
|
-
# has_many :through) associations as they were "at the time", if they are
|
206
|
-
# also being versioned by PaperTrail.
|
207
|
-
#
|
208
212
|
# Options:
|
209
213
|
#
|
210
|
-
# - :has_one
|
211
|
-
# - `true` - Also reify has_one associations.
|
212
|
-
# - `false - Default.
|
213
|
-
# - :has_many
|
214
|
-
# - `true` - Also reify has_many and has_many :through associations.
|
215
|
-
# - `false` - Default.
|
216
214
|
# - :mark_for_destruction
|
217
215
|
# - `true` - Mark the has_one/has_many associations that did not exist in
|
218
216
|
# the reified version for destruction, instead of removing them.
|
@@ -254,13 +252,6 @@ module PaperTrail
|
|
254
252
|
end
|
255
253
|
alias version_author terminator
|
256
254
|
|
257
|
-
def sibling_versions(reload = false)
|
258
|
-
if reload || !defined?(@sibling_versions) || @sibling_versions.nil?
|
259
|
-
@sibling_versions = self.class.with_item_keys(item_type, item_id)
|
260
|
-
end
|
261
|
-
@sibling_versions
|
262
|
-
end
|
263
|
-
|
264
255
|
def next
|
265
256
|
@next ||= sibling_versions.subsequent(self).first
|
266
257
|
end
|
@@ -270,8 +261,9 @@ module PaperTrail
|
|
270
261
|
end
|
271
262
|
|
272
263
|
# Returns an integer representing the chronological position of the
|
273
|
-
# version among its siblings
|
274
|
-
#
|
264
|
+
# version among its siblings. The "create" event, for example, has an index
|
265
|
+
# of 0.
|
266
|
+
#
|
275
267
|
# @api public
|
276
268
|
def index
|
277
269
|
@index ||= RecordHistory.new(sibling_versions, self.class).index(self)
|
@@ -329,7 +321,7 @@ module PaperTrail
|
|
329
321
|
# Enforces the `version_limit`, if set. Default: no limit.
|
330
322
|
# @api private
|
331
323
|
def enforce_version_limit!
|
332
|
-
limit =
|
324
|
+
limit = version_limit
|
333
325
|
return unless limit.is_a? Numeric
|
334
326
|
previous_versions = sibling_versions.not_creates.
|
335
327
|
order(self.class.timestamp_sort_order("asc"))
|
@@ -337,5 +329,26 @@ module PaperTrail
|
|
337
329
|
excess_versions = previous_versions - previous_versions.last(limit)
|
338
330
|
excess_versions.map(&:destroy)
|
339
331
|
end
|
332
|
+
|
333
|
+
# @api private
|
334
|
+
def sibling_versions
|
335
|
+
@sibling_versions ||= self.class.with_item_keys(item_type, item_id)
|
336
|
+
end
|
337
|
+
|
338
|
+
# See docs section 2.e. Limiting the Number of Versions Created.
|
339
|
+
# The version limit can be global or per-model.
|
340
|
+
#
|
341
|
+
# @api private
|
342
|
+
#
|
343
|
+
# TODO: Duplication: similar `constantize` in Reifier#version_reification_class
|
344
|
+
def version_limit
|
345
|
+
if self.class.item_subtype_column_present?
|
346
|
+
klass = (item_subtype || item_type).constantize
|
347
|
+
if klass&.paper_trail_options&.key?(:limit)
|
348
|
+
return klass.paper_trail_options[:limit]
|
349
|
+
end
|
350
|
+
end
|
351
|
+
PaperTrail.config.version_limit
|
352
|
+
end
|
340
353
|
end
|
341
354
|
end
|
@@ -7,9 +7,9 @@ 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 =
|
12
|
-
TINY =
|
10
|
+
MAJOR = 11
|
11
|
+
MINOR = 0
|
12
|
+
TINY = 0
|
13
13
|
|
14
14
|
# Set PRE to nil unless it's a pre-release (beta, rc, etc.)
|
15
15
|
PRE = nil
|
data/lib/paper_trail.rb
CHANGED
@@ -16,6 +16,7 @@ require "active_record"
|
|
16
16
|
|
17
17
|
require "request_store"
|
18
18
|
require "paper_trail/cleaner"
|
19
|
+
require "paper_trail/compatibility"
|
19
20
|
require "paper_trail/config"
|
20
21
|
require "paper_trail/has_paper_trail"
|
21
22
|
require "paper_trail/record_history"
|
@@ -145,3 +146,7 @@ if defined?(::Rails)
|
|
145
146
|
else
|
146
147
|
require "paper_trail/frameworks/active_record"
|
147
148
|
end
|
149
|
+
|
150
|
+
if defined?(::ActiveRecord)
|
151
|
+
::PaperTrail::Compatibility.check_activerecord(::ActiveRecord.gem_version)
|
152
|
+
end
|
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:
|
4
|
+
version: 11.0.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: 2020-08-24 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -18,20 +18,14 @@ dependencies:
|
|
18
18
|
requirements:
|
19
19
|
- - ">="
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '
|
22
|
-
- - "<"
|
23
|
-
- !ruby/object:Gem::Version
|
24
|
-
version: '6.1'
|
21
|
+
version: '5.2'
|
25
22
|
type: :runtime
|
26
23
|
prerelease: false
|
27
24
|
version_requirements: !ruby/object:Gem::Requirement
|
28
25
|
requirements:
|
29
26
|
- - ">="
|
30
27
|
- !ruby/object:Gem::Version
|
31
|
-
version: '
|
32
|
-
- - "<"
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version: '6.1'
|
28
|
+
version: '5.2'
|
35
29
|
- !ruby/object:Gem::Dependency
|
36
30
|
name: request_store
|
37
31
|
requirement: !ruby/object:Gem::Requirement
|
@@ -66,28 +60,28 @@ dependencies:
|
|
66
60
|
requirements:
|
67
61
|
- - "~>"
|
68
62
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
63
|
+
version: '11.0'
|
70
64
|
type: :development
|
71
65
|
prerelease: false
|
72
66
|
version_requirements: !ruby/object:Gem::Requirement
|
73
67
|
requirements:
|
74
68
|
- - "~>"
|
75
69
|
- !ruby/object:Gem::Version
|
76
|
-
version: '
|
70
|
+
version: '11.0'
|
77
71
|
- !ruby/object:Gem::Dependency
|
78
72
|
name: ffaker
|
79
73
|
requirement: !ruby/object:Gem::Requirement
|
80
74
|
requirements:
|
81
75
|
- - "~>"
|
82
76
|
- !ruby/object:Gem::Version
|
83
|
-
version: '2.
|
77
|
+
version: '2.11'
|
84
78
|
type: :development
|
85
79
|
prerelease: false
|
86
80
|
version_requirements: !ruby/object:Gem::Requirement
|
87
81
|
requirements:
|
88
82
|
- - "~>"
|
89
83
|
- !ruby/object:Gem::Version
|
90
|
-
version: '2.
|
84
|
+
version: '2.11'
|
91
85
|
- !ruby/object:Gem::Dependency
|
92
86
|
name: generator_spec
|
93
87
|
requirement: !ruby/object:Gem::Requirement
|
@@ -108,126 +102,132 @@ dependencies:
|
|
108
102
|
requirements:
|
109
103
|
- - "~>"
|
110
104
|
- !ruby/object:Gem::Version
|
111
|
-
version: 0.9.
|
105
|
+
version: 0.9.14
|
112
106
|
type: :development
|
113
107
|
prerelease: false
|
114
108
|
version_requirements: !ruby/object:Gem::Requirement
|
115
109
|
requirements:
|
116
110
|
- - "~>"
|
117
111
|
- !ruby/object:Gem::Version
|
118
|
-
version: 0.9.
|
112
|
+
version: 0.9.14
|
119
113
|
- !ruby/object:Gem::Dependency
|
120
|
-
name:
|
114
|
+
name: rake
|
121
115
|
requirement: !ruby/object:Gem::Requirement
|
122
116
|
requirements:
|
123
117
|
- - "~>"
|
124
118
|
- !ruby/object:Gem::Version
|
125
|
-
version: 0
|
119
|
+
version: '13.0'
|
126
120
|
type: :development
|
127
121
|
prerelease: false
|
128
122
|
version_requirements: !ruby/object:Gem::Requirement
|
129
123
|
requirements:
|
130
124
|
- - "~>"
|
131
125
|
- !ruby/object:Gem::Version
|
132
|
-
version: 0
|
126
|
+
version: '13.0'
|
133
127
|
- !ruby/object:Gem::Dependency
|
134
|
-
name:
|
128
|
+
name: rspec-rails
|
135
129
|
requirement: !ruby/object:Gem::Requirement
|
136
130
|
requirements:
|
137
131
|
- - "~>"
|
138
132
|
- !ruby/object:Gem::Version
|
139
|
-
version:
|
133
|
+
version: '4.0'
|
140
134
|
type: :development
|
141
135
|
prerelease: false
|
142
136
|
version_requirements: !ruby/object:Gem::Requirement
|
143
137
|
requirements:
|
144
138
|
- - "~>"
|
145
139
|
- !ruby/object:Gem::Version
|
146
|
-
version:
|
140
|
+
version: '4.0'
|
147
141
|
- !ruby/object:Gem::Dependency
|
148
|
-
name:
|
142
|
+
name: rubocop
|
149
143
|
requirement: !ruby/object:Gem::Requirement
|
150
144
|
requirements:
|
151
145
|
- - "~>"
|
152
146
|
- !ruby/object:Gem::Version
|
153
|
-
version:
|
147
|
+
version: 0.89.1
|
154
148
|
type: :development
|
155
149
|
prerelease: false
|
156
150
|
version_requirements: !ruby/object:Gem::Requirement
|
157
151
|
requirements:
|
158
152
|
- - "~>"
|
159
153
|
- !ruby/object:Gem::Version
|
160
|
-
version:
|
154
|
+
version: 0.89.1
|
161
155
|
- !ruby/object:Gem::Dependency
|
162
|
-
name:
|
156
|
+
name: rubocop-performance
|
163
157
|
requirement: !ruby/object:Gem::Requirement
|
164
158
|
requirements:
|
165
159
|
- - "~>"
|
166
160
|
- !ruby/object:Gem::Version
|
167
|
-
version:
|
161
|
+
version: 1.7.1
|
168
162
|
type: :development
|
169
163
|
prerelease: false
|
170
164
|
version_requirements: !ruby/object:Gem::Requirement
|
171
165
|
requirements:
|
172
166
|
- - "~>"
|
173
167
|
- !ruby/object:Gem::Version
|
174
|
-
version:
|
168
|
+
version: 1.7.1
|
175
169
|
- !ruby/object:Gem::Dependency
|
176
|
-
name: rspec
|
170
|
+
name: rubocop-rspec
|
177
171
|
requirement: !ruby/object:Gem::Requirement
|
178
172
|
requirements:
|
179
173
|
- - "~>"
|
180
174
|
- !ruby/object:Gem::Version
|
181
|
-
version:
|
175
|
+
version: 1.42.0
|
182
176
|
type: :development
|
183
177
|
prerelease: false
|
184
178
|
version_requirements: !ruby/object:Gem::Requirement
|
185
179
|
requirements:
|
186
180
|
- - "~>"
|
187
181
|
- !ruby/object:Gem::Version
|
188
|
-
version:
|
182
|
+
version: 1.42.0
|
189
183
|
- !ruby/object:Gem::Dependency
|
190
|
-
name:
|
184
|
+
name: mysql2
|
191
185
|
requirement: !ruby/object:Gem::Requirement
|
192
186
|
requirements:
|
193
187
|
- - "~>"
|
194
188
|
- !ruby/object:Gem::Version
|
195
|
-
version: 0.
|
189
|
+
version: '0.5'
|
196
190
|
type: :development
|
197
191
|
prerelease: false
|
198
192
|
version_requirements: !ruby/object:Gem::Requirement
|
199
193
|
requirements:
|
200
194
|
- - "~>"
|
201
195
|
- !ruby/object:Gem::Version
|
202
|
-
version: 0.
|
196
|
+
version: '0.5'
|
203
197
|
- !ruby/object:Gem::Dependency
|
204
|
-
name:
|
198
|
+
name: pg
|
205
199
|
requirement: !ruby/object:Gem::Requirement
|
206
200
|
requirements:
|
207
|
-
- - "
|
201
|
+
- - ">="
|
208
202
|
- !ruby/object:Gem::Version
|
209
|
-
version:
|
203
|
+
version: '0.18'
|
204
|
+
- - "<"
|
205
|
+
- !ruby/object:Gem::Version
|
206
|
+
version: '2.0'
|
210
207
|
type: :development
|
211
208
|
prerelease: false
|
212
209
|
version_requirements: !ruby/object:Gem::Requirement
|
213
210
|
requirements:
|
214
|
-
- - "
|
211
|
+
- - ">="
|
212
|
+
- !ruby/object:Gem::Version
|
213
|
+
version: '0.18'
|
214
|
+
- - "<"
|
215
215
|
- !ruby/object:Gem::Version
|
216
|
-
version:
|
216
|
+
version: '2.0'
|
217
217
|
- !ruby/object:Gem::Dependency
|
218
218
|
name: sqlite3
|
219
219
|
requirement: !ruby/object:Gem::Requirement
|
220
220
|
requirements:
|
221
221
|
- - "~>"
|
222
222
|
- !ruby/object:Gem::Version
|
223
|
-
version: 1.
|
223
|
+
version: '1.4'
|
224
224
|
type: :development
|
225
225
|
prerelease: false
|
226
226
|
version_requirements: !ruby/object:Gem::Requirement
|
227
227
|
requirements:
|
228
228
|
- - "~>"
|
229
229
|
- !ruby/object:Gem::Version
|
230
|
-
version: 1.
|
230
|
+
version: '1.4'
|
231
231
|
description: |
|
232
232
|
Track changes to your models, for auditing or versioning. See how a model looked
|
233
233
|
at any stage in its lifecycle, revert it to any version, or restore it after it
|
@@ -241,7 +241,6 @@ files:
|
|
241
241
|
- lib/generators/paper_trail/install/install_generator.rb
|
242
242
|
- lib/generators/paper_trail/install/templates/add_object_changes_to_versions.rb.erb
|
243
243
|
- lib/generators/paper_trail/install/templates/create_versions.rb.erb
|
244
|
-
- lib/generators/paper_trail/install_generator.rb
|
245
244
|
- lib/generators/paper_trail/migration_generator.rb
|
246
245
|
- lib/generators/paper_trail/update_item_subtype/USAGE
|
247
246
|
- lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb
|
@@ -253,6 +252,7 @@ files:
|
|
253
252
|
- lib/paper_trail/attribute_serializers/object_attribute.rb
|
254
253
|
- lib/paper_trail/attribute_serializers/object_changes_attribute.rb
|
255
254
|
- lib/paper_trail/cleaner.rb
|
255
|
+
- lib/paper_trail/compatibility.rb
|
256
256
|
- lib/paper_trail/config.rb
|
257
257
|
- lib/paper_trail/events/base.rb
|
258
258
|
- lib/paper_trail/events/create.rb
|
@@ -291,7 +291,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
291
291
|
requirements:
|
292
292
|
- - ">="
|
293
293
|
- !ruby/object:Gem::Version
|
294
|
-
version: 2.
|
294
|
+
version: 2.4.0
|
295
295
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
296
296
|
requirements:
|
297
297
|
- - ">="
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "rails/generators"
|
4
|
-
require "rails/generators/active_record"
|
5
|
-
|
6
|
-
module PaperTrail
|
7
|
-
# Installs PaperTrail in a rails app.
|
8
|
-
class InstallGenerator < ::Rails::Generators::Base
|
9
|
-
include ::Rails::Generators::Migration
|
10
|
-
|
11
|
-
# Class names of MySQL adapters.
|
12
|
-
# - `MysqlAdapter` - Used by gems: `mysql`, `activerecord-jdbcmysql-adapter`.
|
13
|
-
# - `Mysql2Adapter` - Used by `mysql2` gem.
|
14
|
-
MYSQL_ADAPTERS = [
|
15
|
-
"ActiveRecord::ConnectionAdapters::MysqlAdapter",
|
16
|
-
"ActiveRecord::ConnectionAdapters::Mysql2Adapter"
|
17
|
-
].freeze
|
18
|
-
|
19
|
-
source_root File.expand_path("templates", __dir__)
|
20
|
-
class_option(
|
21
|
-
:with_changes,
|
22
|
-
type: :boolean,
|
23
|
-
default: false,
|
24
|
-
desc: "Store changeset (diff) with each version"
|
25
|
-
)
|
26
|
-
|
27
|
-
desc "Generates (but does not run) a migration to add a versions table."
|
28
|
-
|
29
|
-
def create_migration_file
|
30
|
-
add_paper_trail_migration("create_versions")
|
31
|
-
add_paper_trail_migration("add_object_changes_to_versions") if options.with_changes?
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.next_migration_number(dirname)
|
35
|
-
::ActiveRecord::Generators::Base.next_migration_number(dirname)
|
36
|
-
end
|
37
|
-
|
38
|
-
protected
|
39
|
-
|
40
|
-
def add_paper_trail_migration(template)
|
41
|
-
migration_dir = File.expand_path("db/migrate")
|
42
|
-
if self.class.migration_exists?(migration_dir, template)
|
43
|
-
::Kernel.warn "Migration already exists: #{template}"
|
44
|
-
else
|
45
|
-
migration_template(
|
46
|
-
"#{template}.rb.erb",
|
47
|
-
"db/migrate/#{template}.rb",
|
48
|
-
item_type_options: item_type_options,
|
49
|
-
migration_version: migration_version,
|
50
|
-
versions_table_options: versions_table_options
|
51
|
-
)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
private
|
56
|
-
|
57
|
-
# MySQL 5.6 utf8mb4 limit is 191 chars for keys used in indexes.
|
58
|
-
# See https://github.com/paper-trail-gem/paper_trail/issues/651
|
59
|
-
def item_type_options
|
60
|
-
opt = { null: false }
|
61
|
-
opt[:limit] = 191 if mysql?
|
62
|
-
", #{opt}"
|
63
|
-
end
|
64
|
-
|
65
|
-
def migration_version
|
66
|
-
major = ActiveRecord::VERSION::MAJOR
|
67
|
-
if major >= 5
|
68
|
-
"[#{major}.#{ActiveRecord::VERSION::MINOR}]"
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
def mysql?
|
73
|
-
MYSQL_ADAPTERS.include?(ActiveRecord::Base.connection.class.name)
|
74
|
-
end
|
75
|
-
|
76
|
-
# Even modern versions of MySQL still use `latin1` as the default character
|
77
|
-
# encoding. Many users are not aware of this, and run into trouble when they
|
78
|
-
# try to use PaperTrail in apps that otherwise tend to use UTF-8. Postgres, by
|
79
|
-
# comparison, uses UTF-8 except in the unusual case where the OS is configured
|
80
|
-
# with a custom locale.
|
81
|
-
#
|
82
|
-
# - https://dev.mysql.com/doc/refman/5.7/en/charset-applications.html
|
83
|
-
# - http://www.postgresql.org/docs/9.4/static/multibyte.html
|
84
|
-
#
|
85
|
-
# Furthermore, MySQL's original implementation of UTF-8 was flawed, and had
|
86
|
-
# to be fixed later by introducing a new charset, `utf8mb4`.
|
87
|
-
#
|
88
|
-
# - https://mathiasbynens.be/notes/mysql-utf8mb4
|
89
|
-
# - https://dev.mysql.com/doc/refman/5.5/en/charset-unicode-utf8mb4.html
|
90
|
-
#
|
91
|
-
def versions_table_options
|
92
|
-
if mysql?
|
93
|
-
', { options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci" }'
|
94
|
-
else
|
95
|
-
""
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|