paper_trail 6.0.2 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/CONTRIBUTING.md +20 -0
- data/.rubocop.yml +30 -2
- data/.rubocop_todo.yml +20 -0
- data/.travis.yml +3 -5
- data/Appraisals +5 -6
- data/CHANGELOG.md +33 -0
- data/README.md +43 -81
- data/Rakefile +1 -1
- data/doc/bug_report_template.rb +4 -2
- data/gemfiles/ar_4.0.gemfile +7 -0
- data/gemfiles/ar_4.2.gemfile +0 -1
- data/lib/generators/paper_trail/templates/create_version_associations.rb +1 -1
- data/lib/generators/paper_trail/templates/create_versions.rb +1 -1
- data/lib/paper_trail.rb +7 -9
- data/lib/paper_trail/config.rb +0 -15
- data/lib/paper_trail/frameworks/rspec.rb +8 -2
- data/lib/paper_trail/model_config.rb +6 -2
- data/lib/paper_trail/record_trail.rb +3 -1
- data/lib/paper_trail/reifier.rb +43 -354
- data/lib/paper_trail/reifiers/belongs_to.rb +48 -0
- data/lib/paper_trail/reifiers/has_and_belongs_to_many.rb +50 -0
- data/lib/paper_trail/reifiers/has_many.rb +110 -0
- data/lib/paper_trail/reifiers/has_many_through.rb +90 -0
- data/lib/paper_trail/reifiers/has_one.rb +76 -0
- data/lib/paper_trail/serializers/yaml.rb +2 -25
- data/lib/paper_trail/version_concern.rb +5 -5
- data/lib/paper_trail/version_number.rb +7 -3
- data/paper_trail.gemspec +7 -34
- data/spec/controllers/articles_controller_spec.rb +1 -1
- data/spec/generators/install_generator_spec.rb +40 -34
- data/spec/models/animal_spec.rb +50 -25
- data/spec/models/boolit_spec.rb +8 -7
- data/spec/models/callback_modifier_spec.rb +13 -13
- data/spec/models/document_spec.rb +21 -0
- data/spec/models/gadget_spec.rb +35 -39
- data/spec/models/joined_version_spec.rb +4 -4
- data/spec/models/json_version_spec.rb +14 -15
- data/spec/models/not_on_update_spec.rb +1 -1
- data/spec/models/post_with_status_spec.rb +2 -2
- data/spec/models/skipper_spec.rb +4 -4
- data/spec/models/thing_spec.rb +1 -1
- data/spec/models/truck_spec.rb +1 -1
- data/spec/models/vehicle_spec.rb +1 -1
- data/spec/models/version_spec.rb +152 -168
- data/spec/models/widget_spec.rb +170 -196
- data/spec/modules/paper_trail_spec.rb +3 -3
- data/spec/modules/version_concern_spec.rb +5 -8
- data/spec/modules/version_number_spec.rb +11 -36
- data/spec/paper_trail/cleaner_spec.rb +152 -0
- data/spec/paper_trail/config_spec.rb +1 -1
- data/spec/paper_trail/serializers/custom_yaml_serializer_spec.rb +45 -0
- data/spec/paper_trail/serializers/json_spec.rb +57 -0
- data/spec/paper_trail/version_limit_spec.rb +55 -0
- data/spec/paper_trail_spec.rb +45 -32
- data/spec/requests/articles_spec.rb +4 -4
- data/test/dummy/app/models/custom_primary_key_record.rb +4 -2
- data/test/dummy/app/models/document.rb +1 -1
- data/test/dummy/app/models/not_on_update.rb +1 -1
- data/test/dummy/app/models/on/create.rb +6 -0
- data/test/dummy/app/models/on/destroy.rb +6 -0
- data/test/dummy/app/models/on/empty_array.rb +6 -0
- data/test/dummy/app/models/on/update.rb +6 -0
- data/test/dummy/app/models/person.rb +1 -0
- data/test/dummy/app/models/song.rb +19 -28
- data/test/dummy/config/application.rb +10 -43
- data/test/dummy/config/routes.rb +1 -1
- data/test/dummy/db/migrate/20110208155312_set_up_test_tables.rb +25 -51
- data/test/dummy/db/schema.rb +29 -19
- data/test/test_helper.rb +0 -16
- data/test/unit/associations_test.rb +81 -81
- data/test/unit/model_test.rb +48 -131
- data/test/unit/serializer_test.rb +34 -45
- data/test/unit/serializers/mixin_json_test.rb +3 -1
- data/test/unit/serializers/yaml_test.rb +1 -5
- metadata +44 -19
- data/lib/paper_trail/frameworks/sinatra.rb +0 -40
- data/test/functional/modular_sinatra_test.rb +0 -46
- data/test/functional/sinatra_test.rb +0 -51
- data/test/unit/cleaner_test.rb +0 -151
- data/test/unit/inheritance_column_test.rb +0 -41
- data/test/unit/serializers/json_test.rb +0 -95
- data/test/unit/serializers/mixin_yaml_test.rb +0 -53
@@ -0,0 +1,48 @@
|
|
1
|
+
module PaperTrail
|
2
|
+
module Reifiers
|
3
|
+
# Reify a single `belongs_to` association of `model`.
|
4
|
+
# @api private
|
5
|
+
module BelongsTo
|
6
|
+
class << self
|
7
|
+
# @api private
|
8
|
+
def reify(assoc, model, options, transaction_id)
|
9
|
+
id = model.send(assoc.foreign_key)
|
10
|
+
version = load_version(assoc, id, transaction_id, options[:version_at])
|
11
|
+
record = load_record(assoc, id, options, version)
|
12
|
+
model.send("#{assoc.name}=".to_sym, record)
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
# Given a `belongs_to` association and a `version`, return a record that
|
18
|
+
# can be assigned in order to reify that association.
|
19
|
+
# @api private
|
20
|
+
def load_record(assoc, id, options, version)
|
21
|
+
if version.nil?
|
22
|
+
assoc.klass.where(assoc.klass.primary_key => id).first
|
23
|
+
else
|
24
|
+
version.reify(
|
25
|
+
options.merge(
|
26
|
+
has_many: false,
|
27
|
+
has_one: false,
|
28
|
+
belongs_to: false,
|
29
|
+
has_and_belongs_to_many: false
|
30
|
+
)
|
31
|
+
)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Given a `belongs_to` association and an `id`, return a version record
|
36
|
+
# from the point in time identified by `transaction_id` or `version_at`.
|
37
|
+
# @api private
|
38
|
+
def load_version(assoc, id, transaction_id, version_at)
|
39
|
+
assoc.klass.paper_trail.version_class.
|
40
|
+
where("item_type = ?", assoc.class_name).
|
41
|
+
where("item_id = ?", id).
|
42
|
+
where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
|
43
|
+
order("id").limit(1).first
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module PaperTrail
|
2
|
+
module Reifiers
|
3
|
+
# Reify a single HABTM association of `model`.
|
4
|
+
# @api private
|
5
|
+
module HasAndBelongsToMany
|
6
|
+
class << self
|
7
|
+
# @api private
|
8
|
+
def reify(pt_enabled, assoc, model, options, transaction_id)
|
9
|
+
version_ids = ::PaperTrail::VersionAssociation.
|
10
|
+
where("foreign_key_name = ?", assoc.name).
|
11
|
+
where("version_id = ?", transaction_id).
|
12
|
+
pluck(:foreign_key_id)
|
13
|
+
|
14
|
+
model.send(assoc.name).proxy_association.target =
|
15
|
+
version_ids.map do |id|
|
16
|
+
if pt_enabled
|
17
|
+
version = load_version(assoc, id, transaction_id, options[:version_at])
|
18
|
+
if version
|
19
|
+
next version.reify(
|
20
|
+
options.merge(
|
21
|
+
has_many: false,
|
22
|
+
has_one: false,
|
23
|
+
belongs_to: false,
|
24
|
+
has_and_belongs_to_many: false
|
25
|
+
)
|
26
|
+
)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
assoc.klass.where(assoc.klass.primary_key => id).first
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
# Given a HABTM association `assoc` and an `id`, return a version record
|
36
|
+
# from the point in time identified by `transaction_id` or `version_at`.
|
37
|
+
# @api private
|
38
|
+
def load_version(assoc, id, transaction_id, version_at)
|
39
|
+
assoc.klass.paper_trail.version_class.
|
40
|
+
where("item_type = ?", assoc.klass.name).
|
41
|
+
where("item_id = ?", id).
|
42
|
+
where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
|
43
|
+
order("id").
|
44
|
+
limit(1).
|
45
|
+
first
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
module PaperTrail
|
2
|
+
module Reifiers
|
3
|
+
# Reify a single, direct (not `through`) `has_many` association of `model`.
|
4
|
+
# @api private
|
5
|
+
module HasMany
|
6
|
+
class << self
|
7
|
+
# @api private
|
8
|
+
def reify(assoc, model, options, transaction_id, version_table_name)
|
9
|
+
versions = load_versions_for_hm_association(
|
10
|
+
assoc,
|
11
|
+
model,
|
12
|
+
version_table_name,
|
13
|
+
transaction_id,
|
14
|
+
options[:version_at]
|
15
|
+
)
|
16
|
+
collection = Array.new model.send(assoc.name).reload # to avoid cache
|
17
|
+
prepare_array(collection, options, versions)
|
18
|
+
model.send(assoc.name).proxy_association.target = collection
|
19
|
+
end
|
20
|
+
|
21
|
+
# Replaces each record in `array` with its reified version, if present
|
22
|
+
# in `versions`.
|
23
|
+
#
|
24
|
+
# @api private
|
25
|
+
# @param array - The collection to be modified.
|
26
|
+
# @param options
|
27
|
+
# @param versions - A `Hash` mapping IDs to `Version`s
|
28
|
+
# @return nil - Always returns `nil`
|
29
|
+
#
|
30
|
+
# Once modified by this method, `array` will be assigned to the
|
31
|
+
# AR association currently being reified.
|
32
|
+
#
|
33
|
+
def prepare_array(array, options, versions)
|
34
|
+
# Iterate each child to replace it with the previous value if there is
|
35
|
+
# a version after the timestamp.
|
36
|
+
array.map! do |record|
|
37
|
+
if (version = versions.delete(record.id)).nil?
|
38
|
+
record
|
39
|
+
elsif version.event == "create"
|
40
|
+
options[:mark_for_destruction] ? record.tap(&:mark_for_destruction) : nil
|
41
|
+
else
|
42
|
+
version.reify(
|
43
|
+
options.merge(
|
44
|
+
has_many: false,
|
45
|
+
has_one: false,
|
46
|
+
belongs_to: false,
|
47
|
+
has_and_belongs_to_many: false
|
48
|
+
)
|
49
|
+
)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Reify the rest of the versions and add them to the collection, these
|
54
|
+
# versions are for those that have been removed from the live
|
55
|
+
# associations.
|
56
|
+
array.concat(
|
57
|
+
versions.values.map { |v|
|
58
|
+
v.reify(
|
59
|
+
options.merge(
|
60
|
+
has_many: false,
|
61
|
+
has_one: false,
|
62
|
+
belongs_to: false,
|
63
|
+
has_and_belongs_to_many: false
|
64
|
+
)
|
65
|
+
)
|
66
|
+
}
|
67
|
+
)
|
68
|
+
|
69
|
+
array.compact!
|
70
|
+
|
71
|
+
nil
|
72
|
+
end
|
73
|
+
|
74
|
+
# Given a SQL fragment that identifies the IDs of version records,
|
75
|
+
# returns a `Hash` mapping those IDs to `Version`s.
|
76
|
+
#
|
77
|
+
# @api private
|
78
|
+
# @param klass - An ActiveRecord class.
|
79
|
+
# @param version_id_subquery - String. A SQL subquery that selects
|
80
|
+
# the IDs of version records.
|
81
|
+
# @return A `Hash` mapping IDs to `Version`s
|
82
|
+
#
|
83
|
+
def versions_by_id(klass, version_id_subquery)
|
84
|
+
klass.
|
85
|
+
paper_trail.version_class.
|
86
|
+
where("id IN (#{version_id_subquery})").
|
87
|
+
inject({}) { |a, e| a.merge!(e.item_id => e) }
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
# Given a `has_many` association on `model`, return the version records
|
93
|
+
# from the point in time identified by `tx_id` or `version_at`.
|
94
|
+
# @api private
|
95
|
+
def load_versions_for_hm_association(assoc, model, version_table, tx_id, version_at)
|
96
|
+
version_id_subquery = ::PaperTrail::VersionAssociation.
|
97
|
+
joins(model.class.version_association_name).
|
98
|
+
select("MIN(version_id)").
|
99
|
+
where("foreign_key_name = ?", assoc.foreign_key).
|
100
|
+
where("foreign_key_id = ?", model.id).
|
101
|
+
where("#{version_table}.item_type = ?", assoc.class_name).
|
102
|
+
where("created_at >= ? OR transaction_id = ?", version_at, tx_id).
|
103
|
+
group("item_id").
|
104
|
+
to_sql
|
105
|
+
versions_by_id(model.class, version_id_subquery)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module PaperTrail
|
2
|
+
module Reifiers
|
3
|
+
# Reify a single HMT association of `model`.
|
4
|
+
# @api private
|
5
|
+
module HasManyThrough
|
6
|
+
class << self
|
7
|
+
# @api private
|
8
|
+
def reify(assoc, model, options, transaction_id)
|
9
|
+
# Load the collection of through-models. For example, if `model` is a
|
10
|
+
# Chapter, having many Paragraphs through Sections, then
|
11
|
+
# `through_collection` will contain Sections.
|
12
|
+
through_collection = model.send(assoc.options[:through])
|
13
|
+
|
14
|
+
# Now, given the collection of "through" models (e.g. sections), load
|
15
|
+
# the collection of "target" models (e.g. paragraphs)
|
16
|
+
collection = collection(through_collection, assoc, options, transaction_id)
|
17
|
+
|
18
|
+
# Finally, assign the `collection` of "target" models, e.g. to
|
19
|
+
# `model.paragraphs`.
|
20
|
+
model.send(assoc.name).proxy_association.target = collection
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
# Examine the `source_reflection`, i.e. the "source" of `assoc` the
|
26
|
+
# `ThroughReflection`. The source can be a `BelongsToReflection`
|
27
|
+
# or a `HasManyReflection`.
|
28
|
+
#
|
29
|
+
# If the association is a has_many association again, then call
|
30
|
+
# reify_has_manys for each record in `through_collection`.
|
31
|
+
#
|
32
|
+
# @api private
|
33
|
+
def collection(through_collection, assoc, options, transaction_id)
|
34
|
+
if !assoc.source_reflection.belongs_to? && through_collection.present?
|
35
|
+
collection_through_has_many(through_collection, assoc, options, transaction_id)
|
36
|
+
else
|
37
|
+
collection_through_belongs_to(through_collection, assoc, options, transaction_id)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# @api private
|
42
|
+
def collection_through_has_many(through_collection, assoc, options, transaction_id)
|
43
|
+
through_collection.each do |through_model|
|
44
|
+
::PaperTrail::Reifier.reify_has_manys(transaction_id, through_model, options)
|
45
|
+
end
|
46
|
+
|
47
|
+
# At this point, the "through" part of the association chain has
|
48
|
+
# been reified, but not the final, "target" part. To continue our
|
49
|
+
# example, `model.sections` (including `model.sections.paragraphs`)
|
50
|
+
# has been loaded. However, the final "target" part of the
|
51
|
+
# association, that is, `model.paragraphs`, has not been loaded. So,
|
52
|
+
# we do that now.
|
53
|
+
through_collection.flat_map { |through_model|
|
54
|
+
through_model.public_send(assoc.name.to_sym).to_a
|
55
|
+
}
|
56
|
+
end
|
57
|
+
|
58
|
+
# @api private
|
59
|
+
def collection_through_belongs_to(through_collection, assoc, options, tx_id)
|
60
|
+
ids = through_collection.map { |through_model|
|
61
|
+
through_model.send(assoc.source_reflection.foreign_key)
|
62
|
+
}
|
63
|
+
versions = load_versions_for_hmt_association(assoc, ids, tx_id, options[:version_at])
|
64
|
+
collection = Array.new assoc.klass.where(assoc.klass.primary_key => ids)
|
65
|
+
Reifiers::HasMany.prepare_array(collection, options, versions)
|
66
|
+
collection
|
67
|
+
end
|
68
|
+
|
69
|
+
# Given a `has_many(through:)` association and an array of `ids`, return
|
70
|
+
# the version records from the point in time identified by `tx_id` or
|
71
|
+
# `version_at`.
|
72
|
+
# @api private
|
73
|
+
def load_versions_for_hmt_association(assoc, ids, tx_id, version_at)
|
74
|
+
version_id_subquery = assoc.klass.paper_trail.version_class.
|
75
|
+
select("MIN(id)").
|
76
|
+
where("item_type = ?", assoc.class_name).
|
77
|
+
where("item_id IN (?)", ids).
|
78
|
+
where(
|
79
|
+
"created_at >= ? OR transaction_id = ?",
|
80
|
+
version_at,
|
81
|
+
tx_id
|
82
|
+
).
|
83
|
+
group("item_id").
|
84
|
+
to_sql
|
85
|
+
Reifiers::HasMany.versions_by_id(assoc.klass, version_id_subquery)
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module PaperTrail
|
2
|
+
module Reifiers
|
3
|
+
# Reify a single `has_one` association of `model`.
|
4
|
+
# @api private
|
5
|
+
module HasOne
|
6
|
+
class << self
|
7
|
+
# @api private
|
8
|
+
def reify(assoc, model, options, transaction_id)
|
9
|
+
version = load_version_for_has_one(assoc, model, transaction_id, options[:version_at])
|
10
|
+
return unless version
|
11
|
+
if version.event == "create"
|
12
|
+
create_event(assoc, model, options)
|
13
|
+
else
|
14
|
+
noncreate_event(assoc, model, options, version)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
# @api private
|
21
|
+
def create_event(assoc, model, options)
|
22
|
+
if options[:mark_for_destruction]
|
23
|
+
model.send(assoc.name).mark_for_destruction if model.send(assoc.name, true)
|
24
|
+
else
|
25
|
+
model.paper_trail.appear_as_new_record do
|
26
|
+
model.send "#{assoc.name}=", nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Given a has-one association `assoc` on `model`, return the version
|
32
|
+
# record from the point in time identified by `transaction_id` or `version_at`.
|
33
|
+
# @api private
|
34
|
+
def load_version_for_has_one(assoc, model, transaction_id, version_at)
|
35
|
+
version_table_name = model.class.paper_trail.version_class.table_name
|
36
|
+
model.class.paper_trail.version_class.joins(:version_associations).
|
37
|
+
where("version_associations.foreign_key_name = ?", assoc.foreign_key).
|
38
|
+
where("version_associations.foreign_key_id = ?", model.id).
|
39
|
+
where("#{version_table_name}.item_type = ?", assoc.class_name).
|
40
|
+
where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
|
41
|
+
order("#{version_table_name}.id ASC").
|
42
|
+
first
|
43
|
+
end
|
44
|
+
|
45
|
+
# @api private
|
46
|
+
def noncreate_event(assoc, model, options, version)
|
47
|
+
child = version.reify(
|
48
|
+
options.merge(
|
49
|
+
has_many: false,
|
50
|
+
has_one: false,
|
51
|
+
belongs_to: false,
|
52
|
+
has_and_belongs_to_many: false
|
53
|
+
)
|
54
|
+
)
|
55
|
+
model.paper_trail.appear_as_new_record do
|
56
|
+
without_persisting(child) do
|
57
|
+
model.send "#{assoc.name}=", child
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Temporarily suppress #save so we can reassociate with the reified
|
63
|
+
# master of a has_one relationship. Since ActiveRecord 5 the related
|
64
|
+
# object is saved when it is assigned to the association. ActiveRecord
|
65
|
+
# 5 also happens to be the first version that provides #suppress.
|
66
|
+
def without_persisting(record)
|
67
|
+
if record.class.respond_to? :suppress
|
68
|
+
record.class.suppress { yield }
|
69
|
+
else
|
70
|
+
yield
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -24,33 +24,10 @@ module PaperTrail
|
|
24
24
|
# value in the serialized `object_changes`.
|
25
25
|
def where_object_changes_condition(arel_field, field, value)
|
26
26
|
# Need to check first (before) and secondary (after) fields
|
27
|
-
m1 =
|
28
|
-
m2 =
|
29
|
-
case yaml_engine_id
|
30
|
-
when :psych
|
31
|
-
m1 = "%\n#{field}:\n- #{value}\n%"
|
32
|
-
m2 = "%\n#{field}:\n-%\n- #{value}\n%"
|
33
|
-
when :syck
|
34
|
-
# Syck adds extra spaces into array dumps
|
35
|
-
m1 = "%\n#{field}: \n%- #{value}\n%"
|
36
|
-
m2 = "%\n#{field}: \n-%\n- #{value}\n%"
|
37
|
-
else
|
38
|
-
raise "Unknown yaml engine"
|
39
|
-
end
|
27
|
+
m1 = "%\n#{field}:\n- #{value}\n%"
|
28
|
+
m2 = "%\n#{field}:\n-%\n- #{value}\n%"
|
40
29
|
arel_field.matches(m1).or(arel_field.matches(m2))
|
41
30
|
end
|
42
|
-
|
43
|
-
# Returns a symbol identifying the YAML engine. Syck was removed from
|
44
|
-
# the ruby stdlib in ruby 2.0, but is still available as a gem.
|
45
|
-
# @api private
|
46
|
-
def yaml_engine_id
|
47
|
-
if (defined?(::YAML::ENGINE) && ::YAML::ENGINE.yamler == "psych") ||
|
48
|
-
(defined?(::Psych) && ::YAML == ::Psych)
|
49
|
-
:psych
|
50
|
-
else
|
51
|
-
:syck
|
52
|
-
end
|
53
|
-
end
|
54
31
|
end
|
55
32
|
end
|
56
33
|
end
|
@@ -162,13 +162,13 @@ module PaperTrail
|
|
162
162
|
# Returns whether the `object` column is using the `json` type supported
|
163
163
|
# by PostgreSQL.
|
164
164
|
def object_col_is_json?
|
165
|
-
|
165
|
+
%i(json jsonb).include?(columns_hash["object"].type)
|
166
166
|
end
|
167
167
|
|
168
168
|
# Returns whether the `object_changes` column is using the `json` type
|
169
169
|
# supported by PostgreSQL.
|
170
170
|
def object_changes_col_is_json?
|
171
|
-
|
171
|
+
%i(json jsonb).include?(columns_hash["object_changes"].try(:type))
|
172
172
|
end
|
173
173
|
end
|
174
174
|
|
@@ -306,13 +306,13 @@ module PaperTrail
|
|
306
306
|
end
|
307
307
|
end
|
308
308
|
|
309
|
-
#
|
310
|
-
# option, and if so enforces it.
|
309
|
+
# Enforces the `version_limit`, if set. Default: no limit.
|
311
310
|
# @api private
|
312
311
|
def enforce_version_limit!
|
313
312
|
limit = PaperTrail.config.version_limit
|
314
313
|
return unless limit.is_a? Numeric
|
315
|
-
previous_versions = sibling_versions.not_creates
|
314
|
+
previous_versions = sibling_versions.not_creates.
|
315
|
+
order(self.class.timestamp_sort_order("asc"))
|
316
316
|
return unless previous_versions.size > limit
|
317
317
|
excess_versions = previous_versions - previous_versions.last(limit)
|
318
318
|
excess_versions.map(&:destroy)
|