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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/test.yml +53 -0
  3. data/.gitignore +2 -0
  4. data/.rubocop.yml +19 -0
  5. data/.ruby-version +1 -0
  6. data/Appraisals +10 -4
  7. data/Gemfile +8 -1
  8. data/README.md +27 -6
  9. data/Rakefile +17 -0
  10. data/gemfiles/rails_7.gemfile +15 -0
  11. data/gemfiles/rails_7.gemfile.lock +212 -0
  12. data/gemfiles/rails_8.gemfile +15 -0
  13. data/gemfiles/rails_8.gemfile.lock +213 -0
  14. data/gemfiles/rails_8_1.gemfile +15 -0
  15. data/gemfiles/rails_8_1.gemfile.lock +143 -0
  16. data/lib/mongo_trails/callback_propagation.rb +77 -0
  17. data/lib/mongo_trails/config.rb +7 -24
  18. data/lib/mongo_trails/events/base.rb +5 -308
  19. data/lib/mongo_trails/model_config.rb +1 -232
  20. data/lib/mongo_trails/mongo_support/config.rb +7 -1
  21. data/lib/mongo_trails/mongo_support/criteria.rb +7 -0
  22. data/lib/mongo_trails/mongo_support/version.rb +242 -19
  23. data/lib/mongo_trails/mongo_support/version_commit_wrap.rb +37 -0
  24. data/lib/mongo_trails/mongo_support/write_version_worker.rb +11 -0
  25. data/lib/mongo_trails/record_trail.rb +21 -262
  26. data/lib/mongo_trails/version.rb +5 -0
  27. data/lib/mongo_trails/version_concern.rb +4 -293
  28. data/lib/mongo_trails.rb +13 -149
  29. data/mongo_trails.gemspec +19 -20
  30. metadata +50 -85
  31. data/.travis.yml +0 -13
  32. data/Gemfile.lock +0 -62
  33. data/gemfiles/rails_5.gemfile +0 -9
  34. data/gemfiles/rails_5.gemfile.lock +0 -63
  35. data/gemfiles/rails_6.gemfile +0 -9
  36. data/gemfiles/rails_6.gemfile.lock +0 -63
  37. data/lib/mongo_trails/attribute_serializers/README.md +0 -10
  38. data/lib/mongo_trails/attribute_serializers/attribute_serializer_factory.rb +0 -27
  39. data/lib/mongo_trails/attribute_serializers/cast_attribute_serializer.rb +0 -51
  40. data/lib/mongo_trails/attribute_serializers/object_attribute.rb +0 -41
  41. data/lib/mongo_trails/attribute_serializers/object_changes_attribute.rb +0 -44
  42. data/lib/mongo_trails/cleaner.rb +0 -60
  43. data/lib/mongo_trails/compatibility.rb +0 -51
  44. data/lib/mongo_trails/events/create.rb +0 -32
  45. data/lib/mongo_trails/events/destroy.rb +0 -42
  46. data/lib/mongo_trails/events/update.rb +0 -60
  47. data/lib/mongo_trails/frameworks/cucumber.rb +0 -33
  48. data/lib/mongo_trails/frameworks/rails/controller.rb +0 -109
  49. data/lib/mongo_trails/frameworks/rails/engine.rb +0 -43
  50. data/lib/mongo_trails/frameworks/rails.rb +0 -4
  51. data/lib/mongo_trails/frameworks/rspec/helpers.rb +0 -29
  52. data/lib/mongo_trails/frameworks/rspec.rb +0 -43
  53. data/lib/mongo_trails/has_paper_trail.rb +0 -86
  54. data/lib/mongo_trails/queries/versions/where_object.rb +0 -65
  55. data/lib/mongo_trails/queries/versions/where_object_changes.rb +0 -75
  56. data/lib/mongo_trails/record_history.rb +0 -51
  57. data/lib/mongo_trails/reifier.rb +0 -130
  58. data/lib/mongo_trails/request.rb +0 -166
  59. data/lib/mongo_trails/serializers/json.rb +0 -46
  60. data/lib/mongo_trails/serializers/yaml.rb +0 -43
  61. data/lib/mongo_trails/type_serializers/postgres_array_serializer.rb +0 -48
  62. data/lib/mongo_trails/version_number.rb +0 -23
@@ -1,178 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PaperTrail
4
- # Configures an ActiveRecord model, mostly at application boot time, but also
5
- # sometimes mid-request, with methods like enable/disable.
6
4
  class ModelConfig
7
- E_CANNOT_RECORD_AFTER_DESTROY = <<-STR.strip_heredoc.freeze
8
- paper_trail.on_destroy(:after) is incompatible with ActiveRecord's
9
- belongs_to_required_by_default. Use on_destroy(:before)
10
- or disable belongs_to_required_by_default.
11
- STR
12
- E_HPT_ABSTRACT_CLASS = <<~STR.squish.freeze
13
- An application model (%s) has been configured to use PaperTrail (via
14
- `has_paper_trail`), but the version model it has been told to use (%s) is
15
- an `abstract_class`. This could happen when an advanced feature called
16
- Custom Version Classes (http://bit.ly/2G4ch0G) is misconfigured. When all
17
- version classes are custom, PaperTrail::Version is configured to be an
18
- `abstract_class`. This is fine, but all application models must be
19
- configured to use concrete (not abstract) version models.
20
- STR
21
- E_MODEL_LIMIT_REQUIRES_ITEM_SUBTYPE = <<~STR.squish.freeze
22
- To use PaperTrail's per-model limit in your %s model, you must have an
23
- item_subtype column in your versions table. See documentation sections
24
- 2.e.1 Per-model limit, and 4.b.1 The optional item_subtype column.
25
- STR
26
- DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION = <<~STR.squish
27
- Passing versions association name as `has_paper_trail versions: %{versions_name}`
28
- is deprecated. Use `has_paper_trail versions: {name: %{versions_name}}` instead.
29
- The hash you pass to `versions:` is now passed directly to `has_many`.
30
- STR
31
- DPR_CLASS_NAME_OPTION = <<~STR.squish
32
- Passing Version class name as `has_paper_trail class_name: %{class_name}`
33
- is deprecated. Use `has_paper_trail versions: {class_name: %{class_name}}`
34
- instead. The hash you pass to `versions:` is now passed directly to `has_many`.
35
- STR
36
-
37
- def initialize(model_class)
38
- @model_class = model_class
39
- end
40
-
41
- # Adds a callback that records a version after a "create" event.
42
- #
43
- # @api public
44
- def on_create
45
- @model_class.after_create { |r|
46
- r.paper_trail.record_create if r.paper_trail.save_version?
47
- }
48
- return if @model_class.paper_trail_options[:on].include?(:create)
49
- @model_class.paper_trail_options[:on] << :create
50
- end
51
-
52
- # Adds a callback that records a version before or after a "destroy" event.
53
- #
54
- # @api public
55
- def on_destroy(recording_order = "before")
56
- unless %w[after before].include?(recording_order.to_s)
57
- raise ArgumentError, 'recording order can only be "after" or "before"'
58
- end
59
-
60
- if recording_order.to_s == "after" && cannot_record_after_destroy?
61
- raise E_CANNOT_RECORD_AFTER_DESTROY
62
- end
63
-
64
- @model_class.send(
65
- "#{recording_order}_destroy",
66
- lambda do |r|
67
- return unless r.paper_trail.save_version?
68
- r.paper_trail.record_destroy(recording_order)
69
- end
70
- )
71
-
72
- return if @model_class.paper_trail_options[:on].include?(:destroy)
73
- @model_class.paper_trail_options[:on] << :destroy
74
- end
75
-
76
- # Adds a callback that records a version after an "update" event.
77
- #
78
- # @api public
79
- def on_update
80
- @model_class.before_save { |r|
81
- r.paper_trail.reset_timestamp_attrs_for_update_if_needed
82
- }
83
- @model_class.after_update { |r|
84
- if r.paper_trail.save_version?
85
- r.paper_trail.record_update(
86
- force: false,
87
- in_after_callback: true,
88
- is_touch: false
89
- )
90
- end
91
- }
92
- @model_class.after_update { |r|
93
- r.paper_trail.clear_version_instance
94
- }
95
- return if @model_class.paper_trail_options[:on].include?(:update)
96
- @model_class.paper_trail_options[:on] << :update
97
- end
98
-
99
- # Adds a callback that records a version after a "touch" event.
100
- # @api public
101
- def on_touch
102
- @model_class.after_touch { |r|
103
- r.paper_trail.record_update(
104
- force: true,
105
- in_after_callback: true,
106
- is_touch: true
107
- )
108
- }
109
- end
110
-
111
- # Set up `@model_class` for PaperTrail. Installs callbacks, associations,
112
- # "class attributes", instance methods, and more.
113
- # @api private
114
- def setup(options = {})
115
- options[:on] ||= %i[create update destroy touch]
116
- options[:on] = Array(options[:on]) # Support single symbol
117
- @model_class.send :include, ::PaperTrail::Model::InstanceMethods
118
- setup_options(options)
119
- setup_associations(options)
120
- check_presence_of_item_subtype_column(options)
121
- @model_class.after_rollback { paper_trail.clear_rolled_back_versions }
122
- setup_callbacks_from_options options[:on]
123
- end
124
-
125
- def version_class
126
- @_version_class ||= @model_class.version_class_name.constantize
127
- end
128
-
129
- private
130
-
131
- # Raises an error if the provided class is an `abstract_class`.
132
- # @api private
133
- def assert_concrete_activerecord_class(class_name)
134
- if class_name.constantize.abstract_class?
135
- raise format(E_HPT_ABSTRACT_CLASS, @model_class, class_name)
136
- end
137
- end
138
-
139
- def cannot_record_after_destroy?
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)
151
- end
152
-
153
- def check_version_class_name(options)
154
- # @api private - `version_class_name`
155
- @model_class.class_attribute :version_class_name
156
- if options[:class_name]
157
- ::ActiveSupport::Deprecation.warn(
158
- format(
159
- DPR_CLASS_NAME_OPTION,
160
- class_name: options[:class_name].inspect
161
- ),
162
- caller(1)
163
- )
164
- options[:versions][:class_name] = options[:class_name]
165
- end
166
- @model_class.version_class_name = options[:versions][:class_name] || "PaperTrail::Version"
167
- end
168
-
169
- def check_versions_association_name(options)
170
- # @api private - versions_association_name
171
- @model_class.class_attribute :versions_association_name
172
- @model_class.versions_association_name = options[:versions][:name] || :versions
173
- end
174
-
175
- def define_has_many_mongo_versions(options)
5
+ def define_has_many_versions(options)
176
6
  options = ensure_versions_option_is_hash(options)
177
7
  check_version_class_name(options)
178
8
  check_versions_association_name(options)
@@ -184,66 +14,5 @@ module PaperTrail
184
14
  end
185
15
  RUBY
186
16
  end
187
-
188
- def ensure_versions_option_is_hash(options)
189
- unless options[:versions].is_a?(Hash)
190
- if options[:versions]
191
- ::ActiveSupport::Deprecation.warn(
192
- format(
193
- DPR_PASSING_ASSOC_NAME_DIRECTLY_TO_VERSIONS_OPTION,
194
- versions_name: options[:versions].inspect
195
- ),
196
- caller(1)
197
- )
198
- end
199
- options[:versions] = {
200
- name: options[:versions]
201
- }
202
- end
203
- options
204
- end
205
-
206
- def get_versions_scope(options)
207
- options[:versions][:scope] || -> { order(model.timestamp_sort_order) }
208
- end
209
-
210
- def setup_associations(options)
211
- # @api private - version_association_name
212
- @model_class.class_attribute :version_association_name
213
- @model_class.version_association_name = options[:version] || :version
214
-
215
- # The version this instance was reified from.
216
- # @api public
217
- @model_class.send :attr_accessor, @model_class.version_association_name
218
-
219
- # @api public - paper_trail_event
220
- @model_class.send :attr_accessor, :paper_trail_event
221
-
222
- define_has_many_mongo_versions(options)
223
- end
224
-
225
- def setup_callbacks_from_options(options_on = [])
226
- options_on.each do |event|
227
- public_send("on_#{event}")
228
- end
229
- end
230
-
231
- def setup_options(options)
232
- # @api public - paper_trail_options - Let's encourage plugins to use eg.
233
- # `paper_trail_options[:versions][:class_name]` rather than
234
- # `version_class_name` because the former is documented and the latter is
235
- # not.
236
- @model_class.class_attribute :paper_trail_options
237
- @model_class.paper_trail_options = options.dup
238
-
239
- %i[ignore skip only].each do |k|
240
- @model_class.paper_trail_options[k] = [@model_class.paper_trail_options[k]].
241
- flatten.
242
- compact.
243
- map { |attr| attr.is_a?(Hash) ? attr.stringify_keys : attr.to_s }
244
- end
245
-
246
- @model_class.paper_trail_options[:meta] ||= {}
247
- end
248
17
  end
249
18
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'mongoid'
2
4
 
3
5
  Mongoid.configure do |config|
@@ -6,4 +8,8 @@ Mongoid.configure do |config|
6
8
  config.log_level = :error
7
9
  end
8
10
 
9
- Mongoid::QueryCache.enabled = false
11
+ if defined?(Mongo::QueryCache)
12
+ Mongo::QueryCache.enabled = false
13
+ elsif defined?(Mongoid::QueryCache)
14
+ Mongoid::QueryCache.enabled = false
15
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Mongoid
4
+ class Criteria
5
+ def reset; end
6
+ end
7
+ end
@@ -1,20 +1,129 @@
1
- require "mongoid"
2
- require "autoinc"
1
+ # frozen_string_literal: true
2
+
3
+ require 'mongoid'
4
+ require 'time'
5
+ require 'mongo_trails/mongo_support/version_commit_wrap'
6
+
7
+ begin
8
+ require 'sidekiq'
9
+ require 'mongo_trails/mongo_support/write_version_worker'
10
+ require 'mongo_trails/mongo_support/criteria'
11
+ rescue LoadError
12
+ # Continue without Sidekiq
13
+ end
3
14
 
4
15
  class AutoIncrementCounters
5
16
  include Mongoid::Document
17
+
18
+ store_in collection: 'auto_increment_counters'
19
+
20
+ field :sequence, type: Integer, default: 0
6
21
  end
7
22
 
8
- module PaperTrail
23
+ PaperTrail.config.has_paper_trail_defaults = { versions: { class_name: 'MongoTrails::Version' } }
24
+
25
+ module MongoTrails
9
26
  class Version
27
+ class << self
28
+ def find(id)
29
+ find_by(integer_id: id)
30
+ end
31
+
32
+ def incrementing_fields
33
+ @incrementing_fields ||= {
34
+ integer_id: {
35
+ scope: -> { MongoTrails::Version.prefix_map },
36
+ step: 1
37
+ }
38
+ }
39
+ end
40
+
41
+ def prefix_map
42
+ (PaperTrail.config.mongo_prefix.is_a?(Proc) && PaperTrail.config.mongo_prefix.call) || 'paper_trail'
43
+ end
44
+
45
+ def next_integer_id
46
+ next_integer_ids(1).first
47
+ end
48
+
49
+ def next_integer_ids(count, scope: prefix_map)
50
+ return [] if count.to_i <= 0
51
+
52
+ counter_id = counter_key(scope)
53
+ ensure_counter_initialized(counter_id, scope)
54
+
55
+ counter = AutoIncrementCounters.collection.find(_id: counter_id).find_one_and_update(
56
+ { '$inc' => { sequence: count } },
57
+ upsert: true,
58
+ return_document: :after
59
+ )
60
+ max_integer_id = counter.fetch('sequence')
61
+
62
+ ((max_integer_id - count + 1)..max_integer_id).to_a
63
+ end
64
+
65
+ def bulk_insert_attributes(version)
66
+ version = version.is_a?(self) ? version : new(version)
67
+ attrs = version.attributes.dup
68
+ attrs.delete('_id') if attrs['_id'].nil?
69
+ attrs
70
+ end
71
+
72
+ def table_name; end
73
+
74
+ def abstract_class?
75
+ false
76
+ end
77
+
78
+ def columns_hash
79
+ fields
80
+ end
81
+
82
+ def column_names
83
+ fields.keys
84
+ end
85
+
86
+ def belongs_to(_name, _options = {}, &block); end
87
+
88
+ def validates_presence_of(_name); end
89
+
90
+ def after_create(_name); end
91
+
92
+ private
93
+
94
+ def counter_key(scope)
95
+ "#{name}:#{scope || prefix_map}"
96
+ end
97
+
98
+ def ensure_counter_initialized(counter_id, _scope)
99
+ existing_counter = AutoIncrementCounters.collection.find(_id: counter_id).first
100
+ return if existing_counter.present?
101
+
102
+ max_id = maximum_existing_integer_id
103
+
104
+ AutoIncrementCounters.collection.find(_id: counter_id).find_one_and_update(
105
+ { '$setOnInsert' => { sequence: max_id } },
106
+ upsert: true,
107
+ return_document: :after
108
+ )
109
+ end
110
+
111
+ def maximum_existing_integer_id
112
+ pipeline = [
113
+ { '$match' => {} },
114
+ { '$group' => { _id: nil, max_integer_id: { '$max' => '$integer_id' } } }
115
+ ]
116
+ Version.collection.aggregate(pipeline).first&.dig('max_integer_id').to_i
117
+ end
118
+ end
119
+
10
120
  include PaperTrail::VersionConcern
11
121
  include Mongoid::Document
12
- include Mongoid::Autoinc
13
122
 
14
- store_in collection: ->() { "#{PaperTrail::Version.prefix_map}_versions" }
123
+ store_in collection: -> { "#{MongoTrails::Version.prefix_map}_versions" }
15
124
 
16
125
  field :item_type, type: String
17
- field :item_id, type: Integer
126
+ field :item_id, type: String
18
127
  field :event, type: String
19
128
  field :whodunnit, type: String
20
129
  field :object, type: Hash
@@ -22,35 +131,149 @@ module PaperTrail
22
131
  field :created_at, type: DateTime
23
132
  field :integer_id, type: Integer
24
133
 
25
- increments :integer_id, scope: -> { PaperTrail::Version.prefix_map }
134
+ index({ item_type: -1, item_id: -1 }, { background: true })
26
135
 
27
- class << self
28
- def reset
29
- Mongoid::QueryCache.clear_cache
30
- end
136
+ before_create :assign_integer_id
31
137
 
32
- def find(id)
33
- find_by(integer_id: id)
34
- end
138
+ attr_accessor :mongo_trails_source_item
35
139
 
36
- def prefix_map
37
- (PaperTrail.config.mongo_prefix.is_a?(Proc) ? PaperTrail.config.mongo_prefix.call : 'paper_trail') || 'paper_trail'
38
- end
140
+ def save_version
141
+ schedule_version_persistence(bang: false)
142
+ end
143
+
144
+ def save_version!
145
+ schedule_version_persistence(bang: true)
39
146
  end
40
147
 
41
148
  def initialize(data)
149
+ data = data.to_h.deep_symbolize_keys
42
150
  item = data.delete(:item)
43
151
  if item.present?
44
152
  data[:item_type] = item.class.name
45
153
  data[:item_id] = item.id
46
154
  end
47
- data[:created_at] = Time.zone&.now || Time.now
155
+ data[:created_at] = normalize_created_at(data[:created_at])
48
156
 
49
157
  super
50
158
  end
51
159
 
52
160
  def item
53
- item_type.constantize.find(item_id)
161
+ item_type.constantize.find_by(id: item_id)
162
+ end
163
+
164
+ def object=(value)
165
+ super(escape_value(value))
166
+ end
167
+
168
+ def object
169
+ unescape_value(super)
170
+ end
171
+
172
+ def object_changes
173
+ unescape_value(super)
174
+ end
175
+
176
+ def object_changes=(value)
177
+ super(escape_value(value))
178
+ end
179
+
180
+ def unescape_value(value)
181
+ value&.deep_transform_keys { |key| parser.unescape(force_utf8(key)) }
182
+ end
183
+
184
+ def escape_value(value)
185
+ value&.deep_transform_keys { |key| parser.escape(force_utf8(key.to_s), /[$.]/) }
186
+ end
187
+
188
+ private
189
+
190
+ def schedule_version_persistence(bang:)
191
+ connection = transaction_connection
192
+ return persist_version(self, bang:) unless connection.transaction_open?
193
+ unless mongo_trails_source_item
194
+ return VersionCommitWrap.new { persist_version(self, bang:) }.add_to_transaction(connection)
195
+ end
196
+
197
+ if (propagation = callback_propagation)
198
+ merge_callback_propagation(propagation, connection:, bang:)
199
+ else
200
+ register_callback_propagation(connection:, bang:)
201
+ end
202
+ end
203
+
204
+ def transaction_connection
205
+ mongo_trails_source_item ? mongo_trails_source_item.class.connection : ActiveRecord::Base.connection
206
+ end
207
+
208
+ def callback_propagation
209
+ return callback_propagations[event] unless event == 'update'
210
+
211
+ callback_propagations[event] || callback_propagations['create']
212
+ end
213
+
214
+ def callback_propagations
215
+ mongo_trails_source_item.instance_variable_get(:@mongo_trails_callback_propagations) ||
216
+ mongo_trails_source_item.instance_variable_set(:@mongo_trails_callback_propagations, {})
217
+ end
218
+
219
+ def register_callback_propagation(connection:, bang:)
220
+ propagation = CallbackPropagation.new(mongo_trails_source_item, self, bang:)
221
+ callback_propagations[event] = propagation
222
+ VersionCommitWrap.new(rollback: -> { propagation.clear }) { propagation.persist }.add_to_transaction(connection)
223
+ end
224
+
225
+ def merge_callback_propagation(propagation, connection:, bang:)
226
+ snapshot = propagation.snapshot
227
+ VersionCommitWrap.new(rollback: -> { propagation.restore!(snapshot) }) {}.add_to_transaction(connection)
228
+ propagation.merge!(self, bang:)
229
+ end
230
+
231
+ def assign_integer_id
232
+ self.integer_id ||= self.class.next_integer_id
233
+ end
234
+
235
+ def normalize_created_at(value)
236
+ return value if value.is_a?(Time) || value.is_a?(DateTime)
237
+ return current_time if value.nil?
238
+
239
+ parse_time(value)
240
+ rescue ArgumentError
241
+ current_time
242
+ end
243
+
244
+ def persist_version(version, bang: false)
245
+ return version.send(:async_save!) if sidekiq_enabled?
246
+
247
+ bang ? version.save! : version.save
248
+ end
249
+
250
+ def parse_time(value)
251
+ time_zone&.parse(value.to_s) || Time.parse(value.to_s)
252
+ end
253
+
254
+ def current_time = time_zone&.now || Time.now
255
+ def time_zone = Time.zone
256
+
257
+ def sidekiq_enabled?
258
+ defined?(Sidekiq) && PaperTrail.config.enable_sidekiq
259
+ end
260
+
261
+ def force_utf8(value)
262
+ value.respond_to?(:force_encoding) ? value.dup.force_encoding('UTF-8') : value
263
+ end
264
+
265
+ def parser
266
+ @parser ||= URI::Parser.new
267
+ end
268
+
269
+ def async_save!
270
+ worker = defined?(PaperTrail.config.sidekiq_worker.queue) ? PaperTrail.config.sidekiq_worker : PaperTrail::WriteVersionWorker
271
+ args = attributes.as_json
272
+ if worker == PaperTrail::WriteVersionWorker
273
+ worker.set(PaperTrail.config.sidekiq_options).perform_async(args)
274
+ else
275
+ worker.perform_async(args)
276
+ end
54
277
  end
55
278
  end
56
279
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ module MongoTrails
4
+ class VersionCommitWrap
5
+ def initialize(rollback: nil, &callback)
6
+ @callback = callback
7
+ @rollback = rollback
8
+ @executed = false
9
+ end
10
+
11
+ def has_transactional_callbacks? # rubocop:disable Naming/PredicatePrefix
12
+ true
13
+ end
14
+
15
+ def trigger_transactional_callbacks?
16
+ true
17
+ end
18
+
19
+ def before_committed!; end
20
+
21
+ def rolledback!(*)
22
+ @executed = true
23
+ @rollback&.call
24
+ end
25
+
26
+ def committed!(**)
27
+ return if @executed
28
+
29
+ @executed = true
30
+ @callback.call
31
+ end
32
+
33
+ def add_to_transaction(connection = ActiveRecord::Base.connection)
34
+ connection.add_transaction_record(self)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PaperTrail
4
+ class WriteVersionWorker
5
+ include Sidekiq::Job
6
+
7
+ def perform(obj)
8
+ MongoTrails::Version.new(obj).save!
9
+ end
10
+ end
11
+ end