activehistory 0.1 → 0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 643c618d011f3af9b72ba7a7fadf3a713aeb0cf4
4
- data.tar.gz: bc2d64e5b59d78deb335733d46eef644defc2656
3
+ metadata.gz: 94d976170424ce9995a019e74e9475ce1036ee85
4
+ data.tar.gz: 3ed68d22d9444cab4a7d1536b5a6514d822a677d
5
5
  SHA512:
6
- metadata.gz: 53870be2424fa9b20e5bea593fb7691f9cd9e92214d558039ec25122f20ef5eb399cdd406c655e71bc978a5fc62289302d8b8be402f3767c210af78245d332bd
7
- data.tar.gz: 4d8b2f3dea6b2aac7922bc8d28868a4b7b6d4f52917d920559f3041ab10fee6e7a5c6fe1aaa661d34b215f5c7f7d8ae6d6690dba93b1bc92ea6b50f0338fed33
6
+ metadata.gz: 448baea6c2bc3e7d3d284491bfcaebf807ef3ac61fe021151065a88a4b6d38b02ef594a6ffe2b115b57fcef420032c4bfc74b3f0a08cbc6a76e7afba4e51b0b6
7
+ data.tar.gz: 202e03ba0ed75936b7ac9f66406f2b1e559449d2eeaa78299793cb65af0d6c18ff06b11da6b1e16931cfb74897dfbac628e416871b0c89cc172c80590653fffe
@@ -4,6 +4,7 @@ PATH
4
4
  activehistory (0.1)
5
5
  activerecord (= 5.0.0.1)
6
6
  arel (~> 7.0)
7
+ globalid (~> 0.3.7)
7
8
 
8
9
  GEM
9
10
  remote: http://rubygems.org/
@@ -21,7 +22,7 @@ GEM
21
22
  tzinfo (~> 1.1)
22
23
  addressable (2.4.0)
23
24
  ansi (1.5.0)
24
- arel (7.1.2)
25
+ arel (7.1.4)
25
26
  builder (3.2.2)
26
27
  concurrent-ruby (1.0.2)
27
28
  crack (0.4.3)
@@ -31,6 +32,8 @@ GEM
31
32
  activesupport (>= 3.0.0)
32
33
  faker (1.6.6)
33
34
  i18n (~> 0.5)
35
+ globalid (0.3.7)
36
+ activesupport (>= 4.1.0)
34
37
  hashdiff (0.3.0)
35
38
  i18n (0.7.0)
36
39
  json (1.8.3)
@@ -87,4 +90,4 @@ DEPENDENCIES
87
90
  webmock
88
91
 
89
92
  BUNDLED WITH
90
- 1.12.5
93
+ 1.13.2
@@ -37,4 +37,5 @@ Gem::Specification.new do |s|
37
37
  # s.add_runtime_dependency 'cookie_store'
38
38
  s.add_runtime_dependency 'arel', '~> 7.0'
39
39
  s.add_runtime_dependency 'activerecord', '5.0.0.1'
40
- end
40
+ s.add_runtime_dependency 'globalid', '~> 0.3.7'
41
+ end
@@ -2,28 +2,41 @@ module ActiveHistory
2
2
 
3
3
  mattr_accessor :connection
4
4
 
5
+ UUIDV4 = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i
6
+
5
7
  def self.configure(settings)
6
8
  @@connection = ActiveHistory::Connection.new(settings)
7
9
  end
8
10
 
9
11
  def self.configured?
10
- class_variable_defined?(:@@connection)
12
+ class_variable_defined?(:@@connection) && !@@connection.nil?
11
13
  end
12
14
 
13
15
  def self.url
14
16
  @@connection.url
15
17
  end
16
18
 
17
- def self.encapsulate(id_or_options=nil)
18
- Thread.current[:activehistory_event] = id_or_options
19
+ def self.encapsulate(attributes_or_event={}, &block)
20
+ if attributes_or_event.is_a?(ActiveHistory::Event)
21
+ event = attributes_or_event
22
+ else
23
+ event = ActiveHistory::Event.new(attributes_or_event)
24
+ end
25
+
26
+ Thread.current[:activehistory_event] = event
27
+
19
28
  yield
20
29
  ensure
21
- if Thread.current[:activehistory_event].is_a?(ActiveHistory::Event)
30
+ if Thread.current[:activehistory_event] && !Thread.current[:activehistory_event].actions.empty?
22
31
  Thread.current[:activehistory_event].save!
23
32
  end
24
33
  Thread.current[:activehistory_event] = nil
25
34
  end
26
35
 
36
+ def self.current_event(timestamp: nil)
37
+ Thread.current[:activehistory_event]
38
+ end
39
+
27
40
  end
28
41
 
29
42
  require 'activehistory/connection'
@@ -1,17 +1,19 @@
1
1
  class ActiveHistory::Action
2
2
 
3
- attr_accessor :type, :timestamp, :subject, :diff
3
+ attr_accessor :type, :timestamp, :subject_type, :subject_id, :diff
4
4
 
5
5
  def initialize(attrs)
6
6
  attrs.each do |k,v|
7
7
  self.send("#{k}=", v)
8
8
  end
9
+ self.diff ||= {}
9
10
  end
10
11
 
11
12
  def as_json
12
13
  {
13
- diff: diff.as_json,
14
- subject: @subject,
14
+ diff: diff.as_json,
15
+ subject_type: @subject_type,
16
+ subject_id: @subject_id,
15
17
  timestamp: @timestamp.iso8601(3),
16
18
  type: @type
17
19
  }
@@ -1,78 +1,135 @@
1
1
  module ActiveHistory::Adapter
2
2
  module ActiveRecord
3
3
  extend ActiveSupport::Concern
4
-
4
+
5
5
  class_methods do
6
6
 
7
7
  def self.extended(other)
8
- other.before_save :activehistory_start
9
- other.before_destroy :activehistory_start
10
-
11
- other.after_create { activehistory_track(:create) }
12
- other.after_update { activehistory_track(:update) }
13
- other.before_destroy { activehistory_track(:destroy) }
14
-
15
- other.after_commit { activehistory_complete }
8
+ other.after_create { activehistory_track(:create) }
9
+ other.after_update { activehistory_track(:update) }
10
+ other.before_destroy { activehistory_track(:destroy) }
16
11
  end
17
12
 
18
13
  def inherited(subclass)
19
14
  super
20
-
21
15
  subclass.instance_variable_set('@activehistory', @activehistory.clone) if defined?(@activehistory)
22
16
  end
23
17
 
24
18
  def track(exclude: [], habtm_model: nil)
25
- @activehistory = {exclude: Array(exclude), habtm_model: habtm_model}
19
+ options = { exclude: Array(exclude) }
20
+ options[:habtm_model] = habtm_model if habtm_model
21
+ @activehistory = options
26
22
  end
27
23
 
28
24
  def has_and_belongs_to_many(name, scope = nil, options = {}, &extension)
29
25
  super
26
+ name = name.to_s
30
27
  habtm_model = self.const_get("HABTM_#{name.to_s.camelize}")
31
28
 
32
29
  habtm_model.track habtm_model: {
33
30
  :left_side => { foreign_key: "#{base_class.name.underscore}_id", inverse_of: name.to_s },
34
- name.to_s.singularize.to_sym => {inverse_of: self.name.underscore.pluralize.to_s}
31
+ name.to_s.singularize.to_sym => { inverse_of: self.name.underscore.pluralize.to_s }
35
32
  }
36
33
 
34
+
37
35
  callback = ->(method, owner, record) {
38
- owner.activehistory_association_udpated(
39
- record.class.reflect_on_association(owner.class.reflect_on_association(name.to_s).options[:inverse_of].to_s),
40
- owner.id,
41
- removed: [record.id],
42
- timestamp: owner.activehistory_timestamp
43
- )
44
- record.activehistory_association_udpated(
45
- owner.class.reflect_on_association(name.to_s),
46
- record.id,
47
- removed: [owner.id],
48
- timestamp: owner.activehistory_timestamp
49
- )
36
+ owner.activehistory_association_changed(name, removed: [record.id])
50
37
  }
51
38
  self.send("after_remove_for_#{name}=", Array(self.send("after_remove_for_#{name}")).compact + [callback])
52
39
  end
53
- end
54
-
55
- def activehistory_id
56
- "#{self.class.name}/#{id}"
40
+
41
+ def activehistory_association_changed(id, reflection_or_relation_name, added: [], removed: [], timestamp: nil, type: :update, propagate: true)
42
+ return if removed.empty? && added.empty?
43
+ reflection = if reflection_or_relation_name.is_a?(String) || reflection_or_relation_name.is_a?(Symbol)
44
+ reflect_on_association(reflection_or_relation_name)
45
+ else
46
+ reflection_or_relation_name
47
+ end
48
+ puts "#{self}##{id}.#{reflection.name} +#{added.inspect} -#{removed.inspect}"
49
+
50
+ action = ActiveHistory.current_event(timestamp: timestamp).action_for(self, id, { type: type, timestamp: timestamp })
51
+
52
+ if reflection.collection?
53
+ diff_key = "#{reflection.name.to_s.singularize}_ids"
54
+ action.diff[diff_key] ||= [[], []]
55
+ action.diff[diff_key][0] |= removed
56
+ action.diff[diff_key][1] |= added
57
+ else
58
+ diff_key = "#{reflection.name.to_s.singularize}_id"
59
+ action.diff[diff_key] ||= [removed.first, added.first]
60
+ end
61
+
62
+
63
+ if propagate && inverse_reflection = reflection.inverse_of
64
+ inverse_klass = inverse_reflection.active_record
65
+
66
+ added.each do |added_id|
67
+ inverse_klass.activehistory_association_changed(added_id, inverse_reflection, {
68
+ added: [id],
69
+ timestamp: timestamp,
70
+ type: type,
71
+ propagate: false
72
+ })
73
+ end
74
+
75
+ removed.each do |removed_id|
76
+ inverse_klass.activehistory_association_changed(removed_id, inverse_reflection, {
77
+ removed: [id],
78
+ timestamp: timestamp,
79
+ type: type,
80
+ propagate: false
81
+ })
82
+ end
83
+ end
84
+ end
85
+
57
86
  end
58
87
 
59
88
  def activehistory_timestamp
60
89
  @activehistory_timestamp ||= Time.now.utc
61
90
  end
62
91
 
63
- def activehistory_start
64
- if activehistory_tracking && !instance_variable_defined?(:@activehistory_finish)
65
- @activehistory_finish = !Thread.current[:activehistory_event]
66
- end
92
+ def with_transaction_returning_status
67
93
  @activehistory_timestamp = Time.now.utc
68
- end
69
-
70
- def activehistory_complete
94
+ if !Thread.current[:activehistory_save_lock]
95
+ run_save = true
96
+ Thread.current[:activehistory_save_lock] = true
97
+ if !Thread.current[:activehistory_event]
98
+ destroy_current_event = true
99
+ Thread.current[:activehistory_event] = ActiveHistory::Event.new(timestamp: @activehistory_timestamp)
100
+ end
101
+ end
102
+
103
+ status = nil
104
+ self.class.transaction do
105
+ add_to_transaction
106
+ begin
107
+ status = yield
108
+ rescue ::ActiveRecord::Rollback
109
+ clear_transaction_record_state
110
+ status = nil
111
+ end
112
+
113
+ if status
114
+ if run_save && ActiveHistory.configured? && !activehistory_event.actions.empty?
115
+ activehistory_event&.save!
116
+ end
117
+ else
118
+ raise ::ActiveRecord::Rollback
119
+ end
120
+ end
121
+ status
122
+ ensure
71
123
  @activehistory_timestamp = nil
72
- if instance_variable_defined?(:@activehistory_finish) && @activehistory_finish && activehistory_tracking
73
- activehistory_event.save! if activehistory_event
124
+ if run_save
125
+ Thread.current[:activehistory_save_lock] = false
126
+ end
127
+ if destroy_current_event
74
128
  Thread.current[:activehistory_event] = nil
75
- @activehistory_timestamp = nil
129
+ end
130
+
131
+ if @transaction_state && @transaction_state.committed?
132
+ clear_transaction_record_state
76
133
  end
77
134
  end
78
135
 
@@ -83,16 +140,7 @@ module ActiveHistory::Adapter
83
140
  end
84
141
 
85
142
  def activehistory_event
86
- case Thread.current[:activehistory_event]
87
- when ActiveHistory::Event
88
- Thread.current[:activehistory_event]
89
- when Hash
90
- Thread.current[:activehistory_event][:timestamp] ||= @activehistory_timestamp
91
- Thread.current[:activehistory_event] = ActiveHistory::Event.new(Thread.current[:activehistory_event])
92
- when Fixnum
93
- else
94
- Thread.current[:activehistory_event] = ActiveHistory::Event.new(timestamp: @activehistory_timestamp)
95
- end
143
+ ActiveHistory.current_event(timestamp: activehistory_timestamp)
96
144
  end
97
145
 
98
146
  def activehistory_track(type)
@@ -111,92 +159,268 @@ module ActiveHistory::Adapter
111
159
  diff = self.attributes.select { |k| !activehistory_tracking[:exclude].include?(k.to_sym) }.map { |k, i| [k, [i, nil]] }.to_h
112
160
  end
113
161
 
114
- return if type == :update && diff.size == 0
162
+ return if type == :update && (diff.keys - (self.send(:timestamp_attributes_for_update) + self.send(:timestamp_attributes_for_create)).map(&:to_s)).empty?
115
163
 
116
- if !activehistory_tracking[:habtm_model]
117
- activehistory_event.action!({
164
+ if activehistory_tracking[:habtm_model]
165
+ if type == :create
166
+ self.class.reflect_on_association(:left_side).klass.activehistory_association_changed(
167
+ self.send(activehistory_tracking[:habtm_model][:left_side][:foreign_key]),
168
+ activehistory_tracking[:habtm_model][:left_side][:inverse_of],
169
+ added: [self.send((self.class.column_names - [activehistory_tracking[:habtm_model][:left_side][:foreign_key]]).first)],
170
+ timestamp: activehistory_timestamp
171
+ )
172
+ end
173
+ else
174
+ activehistory_event.action_for(self.class, id, {
118
175
  type: type,
119
- subject: self.activehistory_id,
120
176
  diff: diff,
121
- timestamp: @activehistory_timestamp
177
+ timestamp: activehistory_timestamp
122
178
  })
123
- end
124
-
125
- self._reflections.each do |key, reflection|
126
- foreign_key = activehistory_tracking.dig(:habtm_model, reflection.name, :foreign_key) || reflection.foreign_key
127
-
128
- if areflection = self.class.reflect_on_association(reflection.name)
129
- if areflection.macro == :has_and_belongs_to_many && type == :create
130
- self.send("#{areflection.name.to_s.singularize}_ids").each do |fid|
131
- next unless fid
132
- activehistory_association_udpated(areflection, fid, added: [diff['id'][1]], timestamp: activehistory_timestamp)
133
- activehistory_association_udpated(areflection.klass.reflect_on_association(areflection.options[:inverse_of]), diff['id'][1], added: [fid], timestamp: activehistory_timestamp, type: :create)
179
+
180
+
181
+ self.class.reflect_on_all_associations.each do |reflection|
182
+ next if activehistory_tracking[:habtm_model]
183
+
184
+ if reflection.macro == :has_and_belongs_to_many && type == :destroy
185
+ activehistory_association_changed(reflection, removed: self.send("#{reflection.name.to_s.singularize}_ids"))
186
+ elsif reflection.macro == :belongs_to && diff.has_key?(reflection.foreign_key)
187
+ case type
188
+ when :create
189
+ old_id = nil
190
+ new_id = diff[reflection.foreign_key][1]
191
+ when :destroy
192
+ old_id = diff[reflection.foreign_key][0]
193
+ new_id = nil
194
+ else
195
+ old_id = diff[reflection.foreign_key][0]
196
+ new_id = diff[reflection.foreign_key][1]
134
197
  end
135
- elsif areflection.macro == :has_and_belongs_to_many && type == :destroy
136
- self.send("#{areflection.name.to_s.singularize}_ids").each do |fid|
137
- activehistory_association_udpated(areflection, fid, removed: [diff['id'][0]], timestamp: activehistory_timestamp, type: :update)
138
- activehistory_association_udpated(areflection.klass.reflect_on_association(areflection.options[:inverse_of]), diff['id'][0], removed: [fid], timestamp: activehistory_timestamp, type: :update)
198
+
199
+ relation_id = self.id || diff.find { |k, v| k != foreign_key }[1][1]
200
+
201
+ if reflection.polymorphic?
202
+ else
203
+ activehistory_association_changed(reflection, removed: [old_id]) if old_id
204
+ activehistory_association_changed(reflection, added: [new_id]) if new_id
139
205
  end
206
+
140
207
  end
141
208
  end
142
-
143
- next unless reflection.macro == :belongs_to && (type == :destroy || diff.has_key?(foreign_key))
144
-
145
- case type
146
- when :create
147
- old_id = nil
148
- new_id = diff[foreign_key][1]
149
- when :destroy
150
- old_id = diff[foreign_key][0]
151
- new_id = nil
152
- else
153
- old_id = diff[foreign_key][0]
154
- new_id = diff[foreign_key][1]
155
- end
156
-
157
- relation_id = self.id || diff.find { |k, v| k != foreign_key }[1][1]
158
-
159
- if reflection.polymorphic?
160
- else
161
- activehistory_association_udpated(reflection, old_id, removed: [relation_id], timestamp: activehistory_timestamp) if old_id
162
- activehistory_association_udpated(reflection, new_id, added: [relation_id], timestamp: activehistory_timestamp) if new_id
163
- end
164
-
165
209
  end
210
+
166
211
 
167
212
  end
168
213
 
214
+ def activehistory_association_changed(relation_name, added: [], removed: [], timestamp: nil, type: :update)
215
+ timestamp ||= activehistory_timestamp
216
+
217
+ self.class.activehistory_association_changed(id, relation_name, {
218
+ added: added,
219
+ removed: removed,
220
+ timestamp: timestamp,
221
+ type: type
222
+ })
223
+
224
+
225
+ end
226
+
169
227
  def activehistory_association_udpated(reflection, id, added: [], removed: [], timestamp: nil, type: :update)
170
- if inverse_of = activehistory_tracking.dig(:habtm_model, reflection.name, :inverse_of)
171
- inverse_of = reflection.klass.reflect_on_association(inverse_of)
228
+ return if !activehistory_tracking || (removed.empty? && added.empty?)
229
+ klass = reflection.active_record
230
+ inverse_klass = reflection.klass
231
+
232
+ inverse_association = if activehistory_tracking.has_key?(:habtm_model)
233
+ inverse_klass.reflect_on_association(activehistory_tracking.dig(:habtm_model, reflection.name.to_s.singularize.to_sym, :inverse_of))
172
234
  else
173
- inverse_of = reflection.inverse_of
235
+ reflection.inverse_of
174
236
  end
175
-
176
- if inverse_of.nil?
237
+
238
+ if inverse_association.nil?
177
239
  puts "NO INVERSE for #{self.class}.#{reflection.name}!!!"
178
240
  return
179
241
  end
180
242
 
181
- model_name = reflection.klass.base_class.model_name.name
182
-
183
- action = activehistory_event.action_for("#{model_name}/#{id}") || activehistory_event.action!({
243
+ action = activehistory_event.action_for(klass, id, {
184
244
  type: type,
185
- subject: "#{model_name}/#{id}",
186
- timestamp: timestamp# || Time.now
245
+ timestamp: timestamp
187
246
  })
188
247
 
189
248
  action.diff ||= {}
190
- if inverse_of.collection? || activehistory_tracking[:habtm_model]
191
- diff_key = "#{inverse_of.name.to_s.singularize}_ids"
249
+ if (reflection.collection? || activehistory_tracking[:habtm_model])
250
+ diff_key = "#{reflection.name.to_s.singularize}_ids"
192
251
  action.diff[diff_key] ||= [[], []]
193
252
  action.diff[diff_key][0] |= removed
194
253
  action.diff[diff_key][1] |= added
195
254
  else
196
- diff_key = "#{inverse_of.name.to_s.singularize}_id"
255
+ diff_key = "#{reflection.name.to_s.singularize}_id"
197
256
  action.diff[diff_key] ||= [removed.first, added.first]
198
257
  end
258
+
259
+ removed.each do |removed_id|
260
+ action = activehistory_event.action_for(inverse_klass, removed_id, {
261
+ type: type,
262
+ timestamp: timestamp
263
+ })
264
+
265
+ action.diff ||= {}
266
+ if inverse_association.collection? || activehistory_tracking[:habtm_model]
267
+ diff_key = "#{inverse_association.name.to_s.singularize}_ids"
268
+ action.diff[diff_key] ||= [[], []]
269
+ action.diff[diff_key][0] |= [id]
270
+ else
271
+ diff_key = "#{inverse_association.name.to_s.singularize}_id"
272
+ action.diff[diff_key] ||= [id, nil]
273
+ end
274
+ end
275
+
276
+ added.each do |added_id|
277
+ action = activehistory_event.action_for(inverse_klass, added_id, {
278
+ type: type,
279
+ timestamp: timestamp
280
+ })
281
+
282
+ action.diff ||= {}
283
+ if inverse_association.collection? || activehistory_tracking[:habtm_model]
284
+ diff_key = "#{inverse_association.name.to_s.singularize}_ids"
285
+ action.diff[diff_key] ||= [[], []]
286
+ action.diff[diff_key][1] |= [id]
287
+ else
288
+ diff_key = "#{inverse_association.name.to_s.singularize}_id"
289
+ action.diff[diff_key] ||= [nil, id]
290
+ end
291
+ end
199
292
  end
200
293
 
201
294
  end
202
- end
295
+ end
296
+
297
+
298
+ module ActiveRecord
299
+ module Associations
300
+ class CollectionAssociation
301
+
302
+ def delete_all(dependent = nil)
303
+ activehistory_encapsulate do
304
+ if dependent && ![:nullify, :delete_all].include?(dependent)
305
+ raise ArgumentError, "Valid values are :nullify or :delete_all"
306
+ end
307
+
308
+ dependent = if dependent
309
+ dependent
310
+ elsif options[:dependent] == :destroy
311
+ :delete_all
312
+ else
313
+ options[:dependent]
314
+ end
315
+
316
+ if dependent == :delete_all
317
+
318
+ else
319
+ removed_ids = self.scope.pluck(:id)
320
+
321
+ action = owner.activehistory_event.action_for(self.reflection.active_record, owner.id, {
322
+ type: :update,
323
+ timestamp: owner.activehistory_timestamp
324
+ })
325
+
326
+ diff_key = "#{self.reflection.name.to_s.singularize}_ids"
327
+ action.diff ||= {}
328
+ action.diff[diff_key] ||= [[], []]
329
+ action.diff[diff_key][0] |= removed_ids
330
+
331
+ ainverse_of = self.klass.reflect_on_association(self.options[:inverse_of])
332
+ if ainverse_of
333
+ removed_ids.each do |removed_id|
334
+ action = owner.activehistory_event.action_for(ainverse_of.active_record, removed_id, {
335
+ type: :update,
336
+ timestamp: owner.activehistory_timestamp
337
+ })
338
+ action.diff ||= {}
339
+ if ainverse_of.collection?
340
+ diff_key = "#{ainverse_of.name.to_s.singularize}_ids"
341
+ action.diff[diff_key] ||= [[], []]
342
+ action.diff[diff_key][0] |= [owner.id]
343
+ else
344
+ diff_key = "#{ainverse_of.name}_id"
345
+ action.diff[diff_key] ||= [owner.id, nil]
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ delete_or_nullify_all_records(dependent).tap do
352
+ reset
353
+ loaded!
354
+ end
355
+ end
356
+ end
357
+
358
+ private
359
+
360
+ def replace_records(new_target, original_target)
361
+ activehistory_encapsulate do
362
+ removed_records = target - new_target
363
+ added_records = new_target - target
364
+
365
+ delete(removed_records)
366
+
367
+ unless concat(added_records)
368
+ @target = original_target
369
+ raise RecordNotSaved, "Failed to replace #{reflection.name} because one or more of the " \
370
+ "new records could not be saved."
371
+ end
372
+
373
+ if !owner.new_record?
374
+ owner.activehistory_association_changed(self.reflection, added: added_records.map(&:id), removed: removed_records.map(&:id))
375
+ end
376
+ end
377
+
378
+ target
379
+ end
380
+
381
+ def delete_or_destroy(records, method)
382
+ activehistory_encapsulate do
383
+ records = records.flatten
384
+ records.each { |record| raise_on_type_mismatch!(record) }
385
+ existing_records = records.reject(&:new_record?)
386
+
387
+ result = if existing_records.empty?
388
+ remove_records(existing_records, records, method)
389
+ else
390
+ transaction { remove_records(existing_records, records, method) }
391
+ end
392
+ end
393
+ end
394
+
395
+ def activehistory_encapsulate
396
+ @activehistory_timestamp = Time.now.utc
397
+ if !Thread.current[:activehistory_save_lock]
398
+ run_save = true
399
+ Thread.current[:activehistory_save_lock] = true
400
+ if !Thread.current[:activehistory_event]
401
+ destroy_current_event = true
402
+ Thread.current[:activehistory_event] = ActiveHistory::Event.new(timestamp: @activehistory_timestamp)
403
+ end
404
+ end
405
+
406
+ result = yield
407
+
408
+ if run_save && ActiveHistory.configured? && !owner.activehistory_event.actions.empty?
409
+ owner.activehistory_event&.save!
410
+ end
411
+
412
+ result
413
+ ensure
414
+ @activehistory_timestamp = nil
415
+ if run_save
416
+ Thread.current[:activehistory_save_lock] = false
417
+ end
418
+ if destroy_current_event
419
+ Thread.current[:activehistory_event] = nil
420
+ end
421
+
422
+ end
423
+
424
+ end
425
+ end
426
+ end