mongo_trails 10.3.1 → 14.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/.github/workflows/test.yml +53 -0
- data/.gitignore +2 -0
- data/.rubocop.yml +19 -0
- data/.ruby-version +1 -0
- data/Appraisals +10 -4
- data/Gemfile +8 -1
- data/README.md +27 -6
- data/Rakefile +17 -0
- data/gemfiles/rails_7.gemfile +15 -0
- data/gemfiles/rails_7.gemfile.lock +212 -0
- data/gemfiles/rails_8.gemfile +15 -0
- data/gemfiles/rails_8.gemfile.lock +213 -0
- data/gemfiles/rails_8_1.gemfile +15 -0
- data/gemfiles/rails_8_1.gemfile.lock +143 -0
- data/lib/mongo_trails/callback_propagation.rb +77 -0
- data/lib/mongo_trails/config.rb +7 -24
- data/lib/mongo_trails/events/base.rb +5 -308
- data/lib/mongo_trails/model_config.rb +1 -232
- data/lib/mongo_trails/mongo_support/config.rb +7 -1
- data/lib/mongo_trails/mongo_support/criteria.rb +7 -0
- data/lib/mongo_trails/mongo_support/version.rb +242 -19
- data/lib/mongo_trails/mongo_support/version_commit_wrap.rb +37 -0
- data/lib/mongo_trails/mongo_support/write_version_worker.rb +11 -0
- data/lib/mongo_trails/record_trail.rb +21 -262
- data/lib/mongo_trails/version.rb +5 -0
- data/lib/mongo_trails/version_concern.rb +4 -293
- data/lib/mongo_trails.rb +13 -149
- data/mongo_trails.gemspec +19 -20
- metadata +50 -85
- data/.travis.yml +0 -13
- data/Gemfile.lock +0 -62
- data/gemfiles/rails_5.gemfile +0 -9
- data/gemfiles/rails_5.gemfile.lock +0 -63
- data/gemfiles/rails_6.gemfile +0 -9
- data/gemfiles/rails_6.gemfile.lock +0 -63
- data/lib/mongo_trails/attribute_serializers/README.md +0 -10
- data/lib/mongo_trails/attribute_serializers/attribute_serializer_factory.rb +0 -27
- data/lib/mongo_trails/attribute_serializers/cast_attribute_serializer.rb +0 -51
- data/lib/mongo_trails/attribute_serializers/object_attribute.rb +0 -41
- data/lib/mongo_trails/attribute_serializers/object_changes_attribute.rb +0 -44
- data/lib/mongo_trails/cleaner.rb +0 -60
- data/lib/mongo_trails/compatibility.rb +0 -51
- data/lib/mongo_trails/events/create.rb +0 -32
- data/lib/mongo_trails/events/destroy.rb +0 -42
- data/lib/mongo_trails/events/update.rb +0 -60
- data/lib/mongo_trails/frameworks/cucumber.rb +0 -33
- data/lib/mongo_trails/frameworks/rails/controller.rb +0 -109
- data/lib/mongo_trails/frameworks/rails/engine.rb +0 -43
- data/lib/mongo_trails/frameworks/rails.rb +0 -4
- data/lib/mongo_trails/frameworks/rspec/helpers.rb +0 -29
- data/lib/mongo_trails/frameworks/rspec.rb +0 -43
- data/lib/mongo_trails/has_paper_trail.rb +0 -86
- data/lib/mongo_trails/queries/versions/where_object.rb +0 -65
- data/lib/mongo_trails/queries/versions/where_object_changes.rb +0 -75
- data/lib/mongo_trails/record_history.rb +0 -51
- data/lib/mongo_trails/reifier.rb +0 -130
- data/lib/mongo_trails/request.rb +0 -166
- data/lib/mongo_trails/serializers/json.rb +0 -46
- data/lib/mongo_trails/serializers/yaml.rb +0 -43
- data/lib/mongo_trails/type_serializers/postgres_array_serializer.rb +0 -48
- data/lib/mongo_trails/version_number.rb +0 -23
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# This file was generated by Appraisal
|
|
4
|
+
|
|
5
|
+
source 'https://rubygems.org'
|
|
6
|
+
|
|
7
|
+
gem 'activerecord', '~> 8.1'
|
|
8
|
+
gem 'after_commit_everywhere'
|
|
9
|
+
gem 'appraisal', '~> 2.3'
|
|
10
|
+
gem 'minitest', '~> 5.0'
|
|
11
|
+
gem 'rake', '~> 13.0'
|
|
12
|
+
gem 'rubocop', require: false
|
|
13
|
+
gem 'sqlite3', '~> 2.9'
|
|
14
|
+
|
|
15
|
+
gemspec path: '../'
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: ..
|
|
3
|
+
specs:
|
|
4
|
+
mongo_trails (14.0.0)
|
|
5
|
+
mongoid (>= 7, < 10)
|
|
6
|
+
ostruct
|
|
7
|
+
paper_trail (~> 16)
|
|
8
|
+
sidekiq (>= 6.5, < 9)
|
|
9
|
+
|
|
10
|
+
GEM
|
|
11
|
+
remote: https://rubygems.org/
|
|
12
|
+
specs:
|
|
13
|
+
activemodel (8.1.3.1)
|
|
14
|
+
activesupport (= 8.1.3.1)
|
|
15
|
+
activerecord (8.1.3.1)
|
|
16
|
+
activemodel (= 8.1.3.1)
|
|
17
|
+
activesupport (= 8.1.3.1)
|
|
18
|
+
timeout (>= 0.4.0)
|
|
19
|
+
activesupport (8.1.3.1)
|
|
20
|
+
base64
|
|
21
|
+
bigdecimal
|
|
22
|
+
concurrent-ruby (~> 1.0, >= 1.3.1)
|
|
23
|
+
connection_pool (>= 2.2.5)
|
|
24
|
+
drb
|
|
25
|
+
i18n (>= 1.6, < 2)
|
|
26
|
+
json
|
|
27
|
+
logger (>= 1.4.2)
|
|
28
|
+
minitest (>= 5.1)
|
|
29
|
+
securerandom (>= 0.3)
|
|
30
|
+
tzinfo (~> 2.0, >= 2.0.5)
|
|
31
|
+
uri (>= 0.13.1)
|
|
32
|
+
after_commit_everywhere (1.6.0)
|
|
33
|
+
activerecord (>= 4.2)
|
|
34
|
+
activesupport
|
|
35
|
+
appraisal (2.5.0)
|
|
36
|
+
bundler
|
|
37
|
+
rake
|
|
38
|
+
thor (>= 0.14.0)
|
|
39
|
+
ast (2.4.3)
|
|
40
|
+
base64 (0.3.0)
|
|
41
|
+
bigdecimal (4.1.2)
|
|
42
|
+
bson (5.2.0)
|
|
43
|
+
concurrent-ruby (1.3.8)
|
|
44
|
+
connection_pool (3.0.2)
|
|
45
|
+
drb (2.2.3)
|
|
46
|
+
i18n (1.15.2)
|
|
47
|
+
concurrent-ruby (~> 1.0)
|
|
48
|
+
json (2.21.2)
|
|
49
|
+
language_server-protocol (3.17.0.5)
|
|
50
|
+
lint_roller (1.1.0)
|
|
51
|
+
logger (1.7.0)
|
|
52
|
+
minitest (5.27.0)
|
|
53
|
+
mongo (2.25.0)
|
|
54
|
+
base64
|
|
55
|
+
bson (>= 4.14.1, < 6.0.0)
|
|
56
|
+
mongoid (9.1.0)
|
|
57
|
+
activemodel (>= 5.1, < 8.2, != 7.0.0)
|
|
58
|
+
concurrent-ruby (>= 1.0.5, < 2.0)
|
|
59
|
+
mongo (>= 2.18.0, < 3.0.0)
|
|
60
|
+
ostruct
|
|
61
|
+
ostruct (0.6.3)
|
|
62
|
+
paper_trail (16.0.0)
|
|
63
|
+
activerecord (>= 6.1)
|
|
64
|
+
request_store (~> 1.4)
|
|
65
|
+
parallel (1.28.0)
|
|
66
|
+
parser (3.3.11.1)
|
|
67
|
+
ast (~> 2.4.1)
|
|
68
|
+
racc
|
|
69
|
+
prism (1.9.0)
|
|
70
|
+
racc (1.8.1)
|
|
71
|
+
rack (3.2.7)
|
|
72
|
+
rainbow (3.1.1)
|
|
73
|
+
rake (13.3.1)
|
|
74
|
+
redis-client (0.30.1)
|
|
75
|
+
connection_pool
|
|
76
|
+
regexp_parser (2.12.0)
|
|
77
|
+
request_store (1.7.0)
|
|
78
|
+
rack (>= 1.4)
|
|
79
|
+
rubocop (1.86.1)
|
|
80
|
+
json (~> 2.3)
|
|
81
|
+
language_server-protocol (~> 3.17.0.2)
|
|
82
|
+
lint_roller (~> 1.1.0)
|
|
83
|
+
parallel (>= 1.10)
|
|
84
|
+
parser (>= 3.3.0.2)
|
|
85
|
+
rainbow (>= 2.2.2, < 4.0)
|
|
86
|
+
regexp_parser (>= 2.9.3, < 3.0)
|
|
87
|
+
rubocop-ast (>= 1.49.0, < 2.0)
|
|
88
|
+
ruby-progressbar (~> 1.7)
|
|
89
|
+
unicode-display_width (>= 2.4.0, < 4.0)
|
|
90
|
+
rubocop-ast (1.49.1)
|
|
91
|
+
parser (>= 3.3.7.2)
|
|
92
|
+
prism (~> 1.7)
|
|
93
|
+
ruby-progressbar (1.13.0)
|
|
94
|
+
securerandom (0.4.1)
|
|
95
|
+
sidekiq (8.1.7)
|
|
96
|
+
connection_pool (>= 3.0.0)
|
|
97
|
+
json (>= 2.16.0)
|
|
98
|
+
logger (>= 1.7.0)
|
|
99
|
+
rack (>= 3.2.0)
|
|
100
|
+
redis-client (>= 0.29.0)
|
|
101
|
+
sqlite3 (2.9.2-aarch64-linux-gnu)
|
|
102
|
+
sqlite3 (2.9.2-aarch64-linux-musl)
|
|
103
|
+
sqlite3 (2.9.2-arm-linux-gnu)
|
|
104
|
+
sqlite3 (2.9.2-arm-linux-musl)
|
|
105
|
+
sqlite3 (2.9.2-arm64-darwin)
|
|
106
|
+
sqlite3 (2.9.2-x86-linux-gnu)
|
|
107
|
+
sqlite3 (2.9.2-x86-linux-musl)
|
|
108
|
+
sqlite3 (2.9.2-x86_64-darwin)
|
|
109
|
+
sqlite3 (2.9.2-x86_64-linux-gnu)
|
|
110
|
+
sqlite3 (2.9.2-x86_64-linux-musl)
|
|
111
|
+
thor (1.5.0)
|
|
112
|
+
timeout (0.6.1)
|
|
113
|
+
tzinfo (2.0.6)
|
|
114
|
+
concurrent-ruby (~> 1.0)
|
|
115
|
+
unicode-display_width (3.2.0)
|
|
116
|
+
unicode-emoji (~> 4.1)
|
|
117
|
+
unicode-emoji (4.2.0)
|
|
118
|
+
uri (1.1.1)
|
|
119
|
+
|
|
120
|
+
PLATFORMS
|
|
121
|
+
aarch64-linux-gnu
|
|
122
|
+
aarch64-linux-musl
|
|
123
|
+
arm-linux-gnu
|
|
124
|
+
arm-linux-musl
|
|
125
|
+
arm64-darwin
|
|
126
|
+
x86-linux-gnu
|
|
127
|
+
x86-linux-musl
|
|
128
|
+
x86_64-darwin
|
|
129
|
+
x86_64-linux-gnu
|
|
130
|
+
x86_64-linux-musl
|
|
131
|
+
|
|
132
|
+
DEPENDENCIES
|
|
133
|
+
activerecord (~> 8.1)
|
|
134
|
+
after_commit_everywhere
|
|
135
|
+
appraisal (~> 2.3)
|
|
136
|
+
minitest (~> 5.0)
|
|
137
|
+
mongo_trails!
|
|
138
|
+
rake (~> 13.0)
|
|
139
|
+
rubocop
|
|
140
|
+
sqlite3 (~> 2.9)
|
|
141
|
+
|
|
142
|
+
BUNDLED WITH
|
|
143
|
+
4.0.19
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module MongoTrails
|
|
4
|
+
class CallbackPropagation
|
|
5
|
+
PRESERVED_ATTRIBUTES = %w[_id item_type item_id event object object_changes integer_id].freeze
|
|
6
|
+
|
|
7
|
+
attr_reader :version
|
|
8
|
+
|
|
9
|
+
def initialize(source, version, bang:)
|
|
10
|
+
@source = source
|
|
11
|
+
@version = version
|
|
12
|
+
@bang = bang
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def merge!(new_version, bang:)
|
|
16
|
+
merge_changes!(new_version.object_changes)
|
|
17
|
+
copy_latest_metadata!(new_version)
|
|
18
|
+
@bang ||= bang
|
|
19
|
+
self
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def snapshot
|
|
23
|
+
{
|
|
24
|
+
object_changes: version.object_changes.to_h.deep_dup,
|
|
25
|
+
metadata: latest_metadata.deep_dup,
|
|
26
|
+
bang: @bang
|
|
27
|
+
}
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def restore!(snapshot)
|
|
31
|
+
version.object_changes = snapshot.fetch(:object_changes)
|
|
32
|
+
snapshot.fetch(:metadata).each { |attribute, value| version[attribute] = value }
|
|
33
|
+
@bang = snapshot.fetch(:bang)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def persist
|
|
37
|
+
version.send(:persist_version, version, bang: @bang)
|
|
38
|
+
ensure
|
|
39
|
+
clear
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def clear
|
|
43
|
+
propagations = @source.instance_variable_get(:@mongo_trails_callback_propagations)
|
|
44
|
+
propagations&.delete(version.event) if propagations&.fetch(version.event, nil).equal?(self)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def merge_changes!(new_changes)
|
|
50
|
+
changes = version.object_changes.to_h.deep_dup
|
|
51
|
+
|
|
52
|
+
new_changes.to_h.each do |attribute, values|
|
|
53
|
+
key = attribute.to_s
|
|
54
|
+
changes[key] = merged_values(changes[key], values)
|
|
55
|
+
changes.delete(key) if unchanged?(changes[key])
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
version.object_changes = changes
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def merged_values(previous_values, new_values)
|
|
62
|
+
previous_values ? [previous_values.first, new_values.last] : new_values
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def unchanged?(values)
|
|
66
|
+
values.first == values.last
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def copy_latest_metadata!(new_version)
|
|
70
|
+
latest_metadata(new_version).each { |attribute, value| version[attribute] = value }
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def latest_metadata(source = version)
|
|
74
|
+
source.attributes.except(*PRESERVED_ATTRIBUTES)
|
|
75
|
+
end
|
|
76
|
+
end
|
|
77
|
+
end
|
data/lib/mongo_trails/config.rb
CHANGED
|
@@ -1,41 +1,24 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "singleton"
|
|
4
|
-
require "mongo_trails/serializers/yaml"
|
|
5
|
-
|
|
6
3
|
module PaperTrail
|
|
7
|
-
# Global configuration affecting all threads. Some thread-specific
|
|
8
|
-
# configuration can be found in `paper_trail.rb`, others in `controller.rb`.
|
|
9
4
|
class Config
|
|
10
|
-
include Singleton
|
|
11
|
-
|
|
12
5
|
attr_accessor(
|
|
13
|
-
:association_reify_error_behaviour,
|
|
14
|
-
:object_changes_adapter,
|
|
15
|
-
:serializer,
|
|
16
|
-
:version_limit,
|
|
17
|
-
:has_paper_trail_defaults,
|
|
18
6
|
:mongo_config,
|
|
19
|
-
:mongo_prefix
|
|
7
|
+
:mongo_prefix,
|
|
8
|
+
:enable_sidekiq,
|
|
9
|
+
:sidekiq_worker,
|
|
10
|
+
:sidekiq_options,
|
|
11
|
+
:mongo_trails_config
|
|
20
12
|
)
|
|
21
13
|
|
|
22
14
|
def initialize
|
|
23
|
-
# Variables which affect all threads, whose access is synchronized.
|
|
24
15
|
@mutex = Mutex.new
|
|
25
16
|
@enabled = true
|
|
26
17
|
|
|
27
|
-
# Variables which affect all threads, whose access is *not* synchronized.
|
|
28
18
|
@serializer = PaperTrail::Serializers::YAML
|
|
29
19
|
@has_paper_trail_defaults = {}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
# Indicates whether PaperTrail is on or off. Default: true.
|
|
33
|
-
def enabled
|
|
34
|
-
@mutex.synchronize { !!@enabled }
|
|
35
|
-
end
|
|
36
|
-
|
|
37
|
-
def enabled=(enable)
|
|
38
|
-
@mutex.synchronize { @enabled = enable }
|
|
20
|
+
@enable_sidekiq = false
|
|
21
|
+
@sidekiq_options = { queue: :default, retry: true, backtrace: false }
|
|
39
22
|
end
|
|
40
23
|
end
|
|
41
24
|
end
|
|
@@ -2,322 +2,19 @@
|
|
|
2
2
|
|
|
3
3
|
module PaperTrail
|
|
4
4
|
module Events
|
|
5
|
-
# We refer to times in the lifecycle of a record as "events". There are
|
|
6
|
-
# three events:
|
|
7
|
-
#
|
|
8
|
-
# - create
|
|
9
|
-
# - `after_create` we call `RecordTrail#record_create`
|
|
10
|
-
# - update
|
|
11
|
-
# - `after_update` we call `RecordTrail#record_update`
|
|
12
|
-
# - `after_touch` we call `RecordTrail#record_update`
|
|
13
|
-
# - `RecordTrail#save_with_version` calls `RecordTrail#record_update`
|
|
14
|
-
# - `RecordTrail#update_columns` is also referred to as an update, though
|
|
15
|
-
# it uses `RecordTrail#record_update_columns` rather than
|
|
16
|
-
# `RecordTrail#record_update`
|
|
17
|
-
# - destroy
|
|
18
|
-
# - `before_destroy` or `after_destroy` we call `RecordTrail#record_destroy`
|
|
19
|
-
#
|
|
20
|
-
# The value inserted into the `event` column of the versions table can also
|
|
21
|
-
# be overridden by the user, with `paper_trail_event`.
|
|
22
|
-
#
|
|
23
|
-
# @api private
|
|
24
5
|
class Base
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
def initialize(record, in_after_callback)
|
|
29
|
-
@record = record
|
|
30
|
-
@in_after_callback = in_after_callback
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
# Determines whether it is appropriate to generate a new version
|
|
34
|
-
# instance. A timestamp-only update (e.g. only `updated_at` changed) is
|
|
35
|
-
# considered notable unless an ignored attribute was also changed.
|
|
36
|
-
#
|
|
37
|
-
# @api private
|
|
38
|
-
def changed_notably?
|
|
39
|
-
if ignored_attr_has_changed?
|
|
40
|
-
timestamps = @record.send(:timestamp_attributes_for_update_in_model).map(&:to_s)
|
|
41
|
-
(notably_changed - timestamps).any?
|
|
42
|
-
else
|
|
43
|
-
notably_changed.any?
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
private
|
|
48
|
-
|
|
49
|
-
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
|
50
|
-
# https://github.com/paper-trail-gem/mongo_trails/pull/899
|
|
51
|
-
#
|
|
52
|
-
# @api private
|
|
53
|
-
def attribute_changed_in_latest_version?(attr_name)
|
|
54
|
-
if @in_after_callback && RAILS_GTE_5_1
|
|
55
|
-
@record.saved_change_to_attribute?(attr_name.to_s)
|
|
56
|
-
else
|
|
57
|
-
@record.attribute_changed?(attr_name.to_s)
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
# @api private
|
|
62
|
-
def nonskipped_attributes_before_change(is_touch)
|
|
63
|
-
cache_changed_attributes do
|
|
64
|
-
record_attributes = @record.attributes.except(*@record.paper_trail_options[:skip])
|
|
65
|
-
|
|
66
|
-
record_attributes.each_key do |k|
|
|
67
|
-
if @record.class.column_names.include?(k)
|
|
68
|
-
record_attributes[k] = attribute_in_previous_version(k, is_touch)
|
|
69
|
-
end
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
# Rails 5.1 changed the API of `ActiveRecord::Dirty`.
|
|
75
|
-
# @api private
|
|
76
|
-
def cache_changed_attributes
|
|
77
|
-
if RAILS_GTE_5_1
|
|
78
|
-
# Everything works fine as it is
|
|
79
|
-
yield
|
|
80
|
-
else
|
|
81
|
-
# Any particular call to `changed_attributes` produces the huge memory allocation.
|
|
82
|
-
# Lets use the generic AR workaround for that.
|
|
83
|
-
@record.send(:cache_changed_attributes) { yield }
|
|
84
|
-
end
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
|
88
|
-
# https://github.com/paper-trail-gem/mongo_trails/pull/899
|
|
89
|
-
#
|
|
90
|
-
# Event can be any of the three (create, update, destroy).
|
|
91
|
-
#
|
|
92
|
-
# @api private
|
|
93
|
-
def attribute_in_previous_version(attr_name, is_touch)
|
|
94
|
-
if RAILS_GTE_5_1
|
|
95
|
-
if @in_after_callback && !is_touch
|
|
96
|
-
# For most events, we want the original value of the attribute, before
|
|
97
|
-
# the last save.
|
|
98
|
-
@record.attribute_before_last_save(attr_name.to_s)
|
|
99
|
-
else
|
|
100
|
-
# We are either performing a `record_destroy` or a
|
|
101
|
-
# `record_update(is_touch: true)`.
|
|
102
|
-
@record.attribute_in_database(attr_name.to_s)
|
|
103
|
-
end
|
|
104
|
-
else
|
|
105
|
-
@record.attribute_was(attr_name.to_s)
|
|
106
|
-
end
|
|
107
|
-
end
|
|
108
|
-
|
|
109
|
-
# @api private
|
|
110
|
-
def calculated_ignored_array
|
|
111
|
-
ignore = @record.paper_trail_options[:ignore].dup
|
|
112
|
-
# Remove Hash arguments and then evaluate whether the attributes (the
|
|
113
|
-
# keys of the hash) should also get pushed into the collection.
|
|
114
|
-
ignore.delete_if do |obj|
|
|
115
|
-
obj.is_a?(Hash) &&
|
|
116
|
-
obj.each { |attr, condition|
|
|
117
|
-
ignore << attr if condition.respond_to?(:call) && condition.call(@record)
|
|
118
|
-
}
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
# @api private
|
|
123
|
-
def changed_and_not_ignored
|
|
124
|
-
skip = @record.paper_trail_options[:skip]
|
|
125
|
-
(changed_in_latest_version - calculated_ignored_array) - skip
|
|
126
|
-
end
|
|
127
|
-
|
|
128
|
-
# @api private
|
|
129
|
-
def changed_in_latest_version
|
|
130
|
-
# Memoized to reduce memory usage
|
|
131
|
-
@changed_in_latest_version ||= changes_in_latest_version.keys
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
# Rails 5.1 changed the API of `ActiveRecord::Dirty`. See
|
|
135
|
-
# https://github.com/paper-trail-gem/mongo_trails/pull/899
|
|
136
|
-
#
|
|
137
|
-
# @api private
|
|
138
|
-
def changes_in_latest_version
|
|
139
|
-
# Memoized to reduce memory usage
|
|
140
|
-
@changes_in_latest_version ||= begin
|
|
141
|
-
if @in_after_callback && RAILS_GTE_5_1
|
|
6
|
+
def load_changes_in_latest_version
|
|
7
|
+
changes =
|
|
8
|
+
if @in_after_callback
|
|
142
9
|
@record.saved_changes
|
|
143
10
|
else
|
|
144
11
|
@record.changes
|
|
145
12
|
end
|
|
146
|
-
end
|
|
147
|
-
end
|
|
148
13
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
# changed.
|
|
152
|
-
#
|
|
153
|
-
# @api private
|
|
154
|
-
def ignored_attr_has_changed?
|
|
155
|
-
ignored = calculated_ignored_array + @record.paper_trail_options[:skip]
|
|
156
|
-
ignored.any? && (changed_in_latest_version & ignored).any?
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
# PT 10 has a new optional column, `item_subtype`
|
|
160
|
-
#
|
|
161
|
-
# @api private
|
|
162
|
-
def merge_item_subtype_into(data)
|
|
163
|
-
if @record.class.paper_trail.version_class.fields.key?("item_subtype")
|
|
164
|
-
data.merge!(item_subtype: @record.class.name)
|
|
14
|
+
changes.delete_if do |_k, v|
|
|
15
|
+
v.is_a?(Array) && v.size > 1 && v.last.is_a?(Hash) && v.uniq.size == 1
|
|
165
16
|
end
|
|
166
17
|
end
|
|
167
|
-
|
|
168
|
-
# Updates `data` from the model's `meta` option and from `controller_info`.
|
|
169
|
-
# Metadata is always recorded; that means all three events (create, update,
|
|
170
|
-
# destroy) and `update_columns`.
|
|
171
|
-
#
|
|
172
|
-
# @api private
|
|
173
|
-
def merge_metadata_into(data)
|
|
174
|
-
merge_metadata_from_model_into(data)
|
|
175
|
-
merge_metadata_from_controller_into(data)
|
|
176
|
-
end
|
|
177
|
-
|
|
178
|
-
# Updates `data` from `controller_info`.
|
|
179
|
-
#
|
|
180
|
-
# @api private
|
|
181
|
-
def merge_metadata_from_controller_into(data)
|
|
182
|
-
data.merge(PaperTrail.request.controller_info || {})
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
# Updates `data` from the model's `meta` option.
|
|
186
|
-
#
|
|
187
|
-
# @api private
|
|
188
|
-
def merge_metadata_from_model_into(data)
|
|
189
|
-
@record.paper_trail_options[:meta].each do |k, v|
|
|
190
|
-
data[k] = model_metadatum(v, data[:event])
|
|
191
|
-
end
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
# Given a `value` from the model's `meta` option, returns an object to be
|
|
195
|
-
# persisted. The `value` can be a simple scalar value, but it can also
|
|
196
|
-
# be a symbol that names a model method, or even a Proc.
|
|
197
|
-
#
|
|
198
|
-
# @api private
|
|
199
|
-
def model_metadatum(value, event)
|
|
200
|
-
if value.respond_to?(:call)
|
|
201
|
-
value.call(@record)
|
|
202
|
-
elsif value.is_a?(Symbol) && @record.respond_to?(value, true)
|
|
203
|
-
# If it is an attribute that is changing in an existing object,
|
|
204
|
-
# be sure to grab the current version.
|
|
205
|
-
if event != "create" &&
|
|
206
|
-
@record.has_attribute?(value) &&
|
|
207
|
-
attribute_changed_in_latest_version?(value)
|
|
208
|
-
attribute_in_previous_version(value, false)
|
|
209
|
-
else
|
|
210
|
-
@record.send(value)
|
|
211
|
-
end
|
|
212
|
-
else
|
|
213
|
-
value
|
|
214
|
-
end
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
# @api private
|
|
218
|
-
def notable_changes
|
|
219
|
-
changes_in_latest_version.delete_if { |k, _v|
|
|
220
|
-
!notably_changed.include?(k)
|
|
221
|
-
}
|
|
222
|
-
end
|
|
223
|
-
|
|
224
|
-
# @api private
|
|
225
|
-
def notably_changed
|
|
226
|
-
# Memoized to reduce memory usage
|
|
227
|
-
@notably_changed ||= begin
|
|
228
|
-
only = @record.paper_trail_options[:only].dup
|
|
229
|
-
# Remove Hash arguments and then evaluate whether the attributes (the
|
|
230
|
-
# keys of the hash) should also get pushed into the collection.
|
|
231
|
-
only.delete_if do |obj|
|
|
232
|
-
obj.is_a?(Hash) &&
|
|
233
|
-
obj.each { |attr, condition|
|
|
234
|
-
only << attr if condition.respond_to?(:call) && condition.call(@record)
|
|
235
|
-
}
|
|
236
|
-
end
|
|
237
|
-
only.empty? ? changed_and_not_ignored : (changed_and_not_ignored & only)
|
|
238
|
-
end
|
|
239
|
-
end
|
|
240
|
-
|
|
241
|
-
# Returns hash of attributes (with appropriate attributes serialized),
|
|
242
|
-
# omitting attributes to be skipped.
|
|
243
|
-
#
|
|
244
|
-
# @api private
|
|
245
|
-
def object_attrs_for_paper_trail(is_touch)
|
|
246
|
-
attrs = nonskipped_attributes_before_change(is_touch)
|
|
247
|
-
AttributeSerializers::ObjectAttribute.new(@record.class).serialize(attrs)
|
|
248
|
-
attrs
|
|
249
|
-
end
|
|
250
|
-
|
|
251
|
-
# @api private
|
|
252
|
-
def prepare_object_changes(changes)
|
|
253
|
-
changes = serialize_object_changes(changes)
|
|
254
|
-
recordable_object_changes(changes)
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
# Returns an object which can be assigned to the `object_changes`
|
|
258
|
-
# attribute of a nascent version record. If the `object_changes` column is
|
|
259
|
-
# a postgres `json` column, then a hash can be used in the assignment,
|
|
260
|
-
# otherwise the column is a `text` column, and we must perform the
|
|
261
|
-
# serialization here, using `PaperTrail.serializer`.
|
|
262
|
-
#
|
|
263
|
-
# @api private
|
|
264
|
-
# @param changes HashWithIndifferentAccess
|
|
265
|
-
def recordable_object_changes(changes)
|
|
266
|
-
if PaperTrail.config.object_changes_adapter&.respond_to?(:diff)
|
|
267
|
-
# We'd like to avoid the `to_hash` here, because it increases memory
|
|
268
|
-
# usage, but that would be a breaking change because
|
|
269
|
-
# `object_changes_adapter` expects a plain `Hash`, not a
|
|
270
|
-
# `HashWithIndifferentAccess`.
|
|
271
|
-
changes = PaperTrail.config.object_changes_adapter.diff(changes.to_hash)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
if @record.class.paper_trail.version_class.object_changes_col_is_json?
|
|
275
|
-
changes
|
|
276
|
-
else
|
|
277
|
-
PaperTrail.serializer.dump(changes)
|
|
278
|
-
end
|
|
279
|
-
end
|
|
280
|
-
|
|
281
|
-
# Returns a boolean indicating whether to store serialized version diffs
|
|
282
|
-
# in the `object_changes` column of the version record.
|
|
283
|
-
#
|
|
284
|
-
# @api private
|
|
285
|
-
def record_object_changes?
|
|
286
|
-
@record.class.paper_trail.version_class.fields.keys.include?("object_changes")
|
|
287
|
-
end
|
|
288
|
-
|
|
289
|
-
# Returns a boolean indicating whether to store the original object during save.
|
|
290
|
-
#
|
|
291
|
-
# @api private
|
|
292
|
-
def record_object?
|
|
293
|
-
@record.class.paper_trail.version_class.fields.keys.include?("object")
|
|
294
|
-
end
|
|
295
|
-
|
|
296
|
-
# Returns an object which can be assigned to the `object` attribute of a
|
|
297
|
-
# nascent version record. If the `object` column is a postgres `json`
|
|
298
|
-
# column, then a hash can be used in the assignment, otherwise the column
|
|
299
|
-
# is a `text` column, and we must perform the serialization here, using
|
|
300
|
-
# `PaperTrail.serializer`.
|
|
301
|
-
#
|
|
302
|
-
# @api private
|
|
303
|
-
def recordable_object(is_touch)
|
|
304
|
-
if @record.class.paper_trail.version_class.object_col_is_json?
|
|
305
|
-
object_attrs_for_paper_trail(is_touch)
|
|
306
|
-
else
|
|
307
|
-
PaperTrail.serializer.dump(object_attrs_for_paper_trail(is_touch))
|
|
308
|
-
end
|
|
309
|
-
end
|
|
310
|
-
|
|
311
|
-
# @api private
|
|
312
|
-
def serialize_object_changes(changes)
|
|
313
|
-
AttributeSerializers::ObjectChangesAttribute.
|
|
314
|
-
new(@record.class).
|
|
315
|
-
serialize(changes)
|
|
316
|
-
|
|
317
|
-
# We'd like to convert this `HashWithIndifferentAccess` to a plain
|
|
318
|
-
# `Hash`, but we don't, to save memory.
|
|
319
|
-
changes
|
|
320
|
-
end
|
|
321
18
|
end
|
|
322
19
|
end
|
|
323
20
|
end
|