snail_trail 1.0.0 → 1.1.0.rc.pre.1

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
  SHA256:
3
- metadata.gz: 39efcc6e2abb6e5e4b2b6ec7db282ee45e1f3532774bee5ce6a02ed877552fdd
4
- data.tar.gz: 2b99c3c9ee205071668045cf89f25afa30c7c143d090a1ae59304cd4a7951a99
3
+ metadata.gz: 9615c601651c566fd33af08844a5aa454394269af10c4b955c95864ccf364963
4
+ data.tar.gz: 4656e2e38cfb1ed9155ec37b676e46e4cd8533c5db54118c69e55177d95223d2
5
5
  SHA512:
6
- metadata.gz: dd558bd7231683b7a20a8536be9b823137001011b3665f6ef50d5ab3f1cee0370624a97547a64679470e5f66f1697fc6800a55df23f4c8797caf0b682b0c60f2
7
- data.tar.gz: adefeb14072c54f5b8e629c8ae8d50b5d87dd78f6e8adc2ad061e7d8e51077c224fed26c28cec37a0a6668123c1e23e406bd1913fc6632879a745959fcce8848
6
+ metadata.gz: 32cb46bf800abafcf3b16efd74ace9e398cf7cb366310ed48bdc2cd14ec375036543e3699d9f97359cfa4a2c42882c67d555fab442bfd93ae3902f54ff020547
7
+ data.tar.gz: 3377f9f5af34d50de4dcaca784fb1b6d6cb8190801496418b02a7aefc7494801f92bac6172b5c0d83c13dd3b976f0dc285868c1fa24556f71d89dedb9cdb4ab6
@@ -89,6 +89,16 @@ module SnailTrail
89
89
  end
90
90
  end
91
91
 
92
+ # Tells SnailTrail to run in performance mode.
93
+ #
94
+ # @api public
95
+ #
96
+ def set_snail_trail_performance_mode
97
+ if ::SnailTrail.request.enabled?
98
+ ::SnailTrail.request.performance_mode!
99
+ end
100
+ end
101
+
92
102
  # Tells SnailTrail any information from the controller you want to store
93
103
  # alongside any changes that occur.
94
104
  #
@@ -126,8 +126,18 @@ module SnailTrail
126
126
 
127
127
  # Reset the transaction id when the transaction is closed.
128
128
  def setup_transaction_callbacks
129
- @model_class.after_commit { ::SnailTrail.request.clear_transaction_id }
130
- @model_class.after_rollback { ::SnailTrail.request.clear_transaction_id }
129
+ @model_class.after_commit do |r|
130
+ ::SnailTrail.request.clear_transaction_id
131
+
132
+ r.snail_trail.record_performance_data
133
+
134
+ ::SnailTrail.request.clear_performance_mode
135
+ end
136
+
137
+ @model_class.after_rollback do
138
+ ::SnailTrail.request.clear_transaction_id
139
+ ::SnailTrail.request.clear_performance_mode
140
+ end
131
141
  end
132
142
 
133
143
  # @api private
@@ -58,17 +58,23 @@ module SnailTrail
58
58
  def record_create
59
59
  return unless enabled?
60
60
 
61
- build_version_on_create(in_after_callback: true).tap do |version|
62
- version.save!
61
+ version = build_version_on_create(in_after_callback: true)
63
62
 
64
- update_transaction_id(version)
63
+ if ::SnailTrail.request.performance_mode?
64
+ ::SnailTrail.request.performance_mode_data << version.attributes
65
+ else
66
+ begin
67
+ version.save!
65
68
 
66
- # Because the version object was created using version_class.new instead
67
- # of versions_assoc.build?, the association cache is unaware. So, we
68
- # invalidate the `versions` association cache with `reset`.
69
- versions.reset
70
- rescue StandardError => e
71
- handle_version_errors e, version, :create
69
+ update_transaction_id(version)
70
+
71
+ # Because the version object was created using version_class.new instead
72
+ # of versions_assoc.build?, the association cache is unaware. So, we
73
+ # invalidate the `versions` association cache with `reset`.
74
+ versions.reset
75
+ rescue StandardError => e
76
+ handle_version_errors e, version, :create
77
+ end
72
78
  end
73
79
  end
74
80
 
@@ -82,22 +88,25 @@ module SnailTrail
82
88
  in_after_callback = recording_order == "after"
83
89
  event = Events::Destroy.new(@record, in_after_callback)
84
90
 
85
- # Merge data from `Event` with data from ST-AT. We no longer use
86
- # `data_for_destroy` but ST-AT still does.
87
91
  data = event.data.merge(data_for_destroy)
88
92
 
89
93
  version = @record.class.snail_trail.version_class.new(data)
90
- begin
91
- version.save!
92
- assign_and_reset_version_association(version)
93
94
 
94
- if version && version.respond_to?(:errors) && version.errors.empty?
95
- update_transaction_id(version)
96
- end
95
+ if ::SnailTrail.request.performance_mode?
96
+ ::SnailTrail.request.performance_mode_data << version.attributes
97
+ else
98
+ begin
99
+ version.save!
100
+ assign_and_reset_version_association(version)
101
+
102
+ if version && version.respond_to?(:errors) && version.errors.empty?
103
+ update_transaction_id(version)
104
+ end
97
105
 
98
- version
99
- rescue StandardError => e
100
- handle_version_errors e, version, :destroy
106
+ version
107
+ rescue StandardError => e
108
+ handle_version_errors e, version, :destroy
109
+ end
101
110
  end
102
111
  end
103
112
 
@@ -119,20 +128,50 @@ module SnailTrail
119
128
  )
120
129
  return unless version
121
130
 
122
- begin
123
- version.save!
124
- # Because the version object was created using version_class.new instead
125
- # of versions_assoc.build?, the association cache is unaware. So, we
126
- # invalidate the `versions` association cache with `reset`.
127
- versions.reset
131
+ if ::SnailTrail.request.performance_mode?
132
+ ::SnailTrail.request.performance_mode_data << version.attributes
133
+ else
134
+ begin
135
+ version.save!
136
+ # Because the version object was created using version_class.new instead
137
+ # of versions_assoc.build?, the association cache is unaware. So, we
138
+ # invalidate the `versions` association cache with `reset`.
139
+ versions.reset
140
+
141
+ if version && version.respond_to?(:errors) && version.errors.empty?
142
+ update_transaction_id(version)
143
+ end
144
+
145
+ version
146
+ rescue StandardError => e
147
+ handle_version_errors e, version, :update
148
+ end
149
+ end
150
+ end
151
+
152
+ def record_performance_data
153
+ return unless ::SnailTrail.request.performance_mode?
154
+
155
+ all_data = ::SnailTrail.request.performance_mode_data
156
+ first_data = all_data.shift
157
+ version = @record.class.snail_trail.version_class.create(first_data)
158
+ update_transaction_id(version)
159
+ all_data.each_slice(1_000) do |datas|
160
+ timestamp = Time.now.utc.strftime("%Y-%m-%d %H:%M:%S")
161
+ datas.each do |d|
162
+ add_transaction_id_to(d)
163
+ d['created_at'] = timestamp
164
+ d['event'] = "batch_#{d['event']}"
165
+ end
128
166
 
129
- if version && version.respond_to?(:errors) && version.errors.empty?
130
- update_transaction_id(version)
167
+ sql = ["INSERT INTO #{version.class.table_name} (#{datas.first.keys.join(", ")}) VALUES"]
168
+ datas.map do |data|
169
+ values = data.map { |k, v| @record.class.connection.quote(v.is_a?(Hash) ? JSON.generate(v) : v) }
170
+ sql << "(#{values.join(", ")}),"
131
171
  end
172
+ sql.last.chop!
132
173
 
133
- version
134
- rescue StandardError => e
135
- handle_version_errors e, version, :update
174
+ @record.class.snail_trail.version_class.connection.execute(sql.join("\n"))
136
175
  end
137
176
  end
138
177
 
@@ -218,7 +257,6 @@ module SnailTrail
218
257
  data[:transaction_id] = ::SnailTrail.request.transaction_id
219
258
  end
220
259
 
221
-
222
260
  def update_transaction_id(version)
223
261
  return unless @record.class.snail_trail.version_class.column_names.include?("transaction_id")
224
262
  if ::SnailTrail.transaction? && ::SnailTrail.request.transaction_id.nil?
@@ -228,148 +266,148 @@ module SnailTrail
228
266
  end
229
267
  end
230
268
 
231
- # @api private
232
- def assign_and_reset_version_association(version)
233
- @record.send(:"#{@record.class.version_association_name}=", version)
234
- @record.send(@record.class.versions_association_name).reset
235
- end
236
-
237
- # @api private
238
- def build_version_on_create(in_after_callback:)
239
- event = Events::Create.new(@record, in_after_callback)
269
+ # @api private
270
+ def assign_and_reset_version_association(version)
271
+ @record.send(:"#{@record.class.version_association_name}=", version)
272
+ @record.send(@record.class.versions_association_name).reset
273
+ end
240
274
 
241
- # Merge data from `Event` with data from ST-AT. We no longer use
242
- # `data_for_create` but ST-AT still does.
243
- data = event.data.merge!(data_for_create)
275
+ # @api private
276
+ def build_version_on_create(in_after_callback:)
277
+ event = Events::Create.new(@record, in_after_callback)
244
278
 
245
- # Pure `version_class.new` reduces memory usage compared to `versions_assoc.build`
246
- @record.class.snail_trail.version_class.new(data)
247
- end
279
+ # Merge data from `Event` with data from ST-AT. We no longer use
280
+ # `data_for_create` but ST-AT still does.
281
+ data = event.data.merge!(data_for_create)
248
282
 
249
- # @api private
250
- def build_version_on_update(force:, in_after_callback:, is_touch:)
251
- event = Events::Update.new(@record, in_after_callback, is_touch, nil)
252
- return unless force || event.changed_notably?
253
- data = event.data
254
-
255
- # Copy the (recently set) `updated_at` from the record to the `created_at`
256
- # of the `Version`. Without this feature, these two timestamps would
257
- # differ by a few milliseconds. To some people, it seems a little
258
- # unnatural to tamper with creation timestamps in this way. But, this
259
- # feature has existed for a long time, almost a decade now, and some users
260
- # may rely on it now.
261
- if @record.respond_to?(:updated_at) &&
262
- @record.snail_trail_options[:synchronize_version_creation_timestamp] != false
263
- data[:created_at] = @record.updated_at
283
+ # Pure `version_class.new` reduces memory usage compared to `versions_assoc.build`
284
+ @record.class.snail_trail.version_class.new(data)
264
285
  end
265
286
 
266
- # Merge data from `Event` with data from ST-AT. We no longer use
267
- # `data_for_update` but ST-AT still does. To save memory, we use `merge!`
268
- # instead of `merge`.
269
- data.merge!(data_for_update)
287
+ # @api private
288
+ def build_version_on_update(force:, in_after_callback:, is_touch:)
289
+ event = Events::Update.new(@record, in_after_callback, is_touch, nil)
290
+ return unless force || event.changed_notably?
291
+ data = event.data
292
+
293
+ # Copy the (recently set) `updated_at` from the record to the `created_at`
294
+ # of the `Version`. Without this feature, these two timestamps would
295
+ # differ by a few milliseconds. To some people, it seems a little
296
+ # unnatural to tamper with creation timestamps in this way. But, this
297
+ # feature has existed for a long time, almost a decade now, and some users
298
+ # may rely on it now.
299
+ if @record.respond_to?(:updated_at) &&
300
+ @record.snail_trail_options[:synchronize_version_creation_timestamp] != false
301
+ data[:created_at] = @record.updated_at
302
+ end
270
303
 
271
- # Using `version_class.new` reduces memory usage compared to
272
- # `versions_assoc.build`. It's a trade-off though. We have to clear
273
- # the association cache (see `versions.reset`) and that could cause an
274
- # additional query in certain applications.
275
- @record.class.snail_trail.version_class.new(data)
276
- end
304
+ # Merge data from `Event` with data from ST-AT. We no longer use
305
+ # `data_for_update` but ST-AT still does. To save memory, we use `merge!`
306
+ # instead of `merge`.
307
+ data.merge!(data_for_update)
277
308
 
278
- # @api public
279
- def data_for_create
280
- data = {}
281
- add_transaction_id_to(data)
282
- data
283
- end
309
+ # Using `version_class.new` reduces memory usage compared to
310
+ # `versions_assoc.build`. It's a trade-off though. We have to clear
311
+ # the association cache (see `versions.reset`) and that could cause an
312
+ # additional query in certain applications.
313
+ @record.class.snail_trail.version_class.new(data)
314
+ end
284
315
 
285
- # @api public
286
- def data_for_destroy
287
- data = {}
288
- add_transaction_id_to(data)
289
- data
290
- end
316
+ # @api public
317
+ def data_for_create
318
+ data = {}
319
+ add_transaction_id_to(data)
320
+ data
321
+ end
291
322
 
292
- # @api public
293
- def data_for_update
294
- data = {}
295
- add_transaction_id_to(data)
296
- data
297
- end
323
+ # @api public
324
+ def data_for_destroy
325
+ data = {}
326
+ add_transaction_id_to(data)
327
+ data
328
+ end
298
329
 
299
- # @api public
300
- def data_for_update_columns
301
- data = {}
302
- add_transaction_id_to(data)
303
- data
304
- end
330
+ # @api public
331
+ def data_for_update
332
+ data = {}
333
+ add_transaction_id_to(data)
334
+ data
335
+ end
305
336
 
306
- # Is ST enabled for this particular record?
307
- # @api private
308
- def enabled?
309
- SnailTrail.enabled? &&
310
- SnailTrail.request.enabled? &&
311
- SnailTrail.request.enabled_for_model?(@record.class)
312
- end
337
+ # @api public
338
+ def data_for_update_columns
339
+ data = {}
340
+ add_transaction_id_to(data)
341
+ data
342
+ end
313
343
 
314
- def log_version_errors(version, action)
315
- version.logger&.warn(
316
- "Unable to create version for #{action} of #{@record.class.name}" \
317
- "##{@record.id}: " + version.errors.full_messages.join(", ")
318
- )
319
- end
344
+ # Is ST enabled for this particular record?
345
+ # @api private
346
+ def enabled?
347
+ SnailTrail.enabled? &&
348
+ SnailTrail.request.enabled? &&
349
+ SnailTrail.request.enabled_for_model?(@record.class)
350
+ end
320
351
 
321
- # Centralized handler for version errors
322
- # @api private
323
- def handle_version_errors(e, version, action)
324
- case SnailTrail.config.version_error_behavior
325
- when :legacy
326
- # legacy behavior was to raise on create and log on update/delete
327
- if action == :create
328
- raise e
329
- else
352
+ def log_version_errors(version, action)
353
+ version.logger&.warn(
354
+ "Unable to create version for #{action} of #{@record.class.name}" \
355
+ "##{@record.id}: " + version.errors.full_messages.join(", ")
356
+ )
357
+ end
358
+
359
+ # Centralized handler for version errors
360
+ # @api private
361
+ def handle_version_errors(e, version, action)
362
+ case SnailTrail.config.version_error_behavior
363
+ when :legacy
364
+ # legacy behavior was to raise on create and log on update/delete
365
+ if action == :create
366
+ raise e
367
+ else
368
+ log_version_errors(version, action)
369
+ end
370
+ when :log
330
371
  log_version_errors(version, action)
372
+ when :exception
373
+ raise e
374
+ when :silent
375
+ # noop
331
376
  end
332
- when :log
333
- log_version_errors(version, action)
334
- when :exception
335
- raise e
336
- when :silent
337
- # noop
338
377
  end
339
- end
340
-
341
- # @api private
342
- # @return - The created version object, so that plugins can use it, e.g.
343
- # snail_trail-association_tracking
344
- def record_update_columns(changes)
345
- return unless enabled?
346
- data = Events::Update.new(@record, false, false, changes).data
347
-
348
- # Merge data from `Event` with data from ST-AT. We no longer use
349
- # `data_for_update_columns` but ST-AT still does.
350
- data.merge!(data_for_update_columns)
351
-
352
- versions_assoc = @record.send(@record.class.versions_association_name)
353
- version = versions_assoc.new(data)
354
- begin
355
- version.save!
356
378
 
357
- if version && version.respond_to?(:errors) && version.errors.empty?
358
- update_transaction_id(version)
379
+ # @api private
380
+ # @return - The created version object, so that plugins can use it, e.g.
381
+ # snail_trail-association_tracking
382
+ def record_update_columns(changes)
383
+ return unless enabled?
384
+ data = Events::Update.new(@record, false, false, changes).data
385
+
386
+ # Merge data from `Event` with data from ST-AT. We no longer use
387
+ # `data_for_update_columns` but ST-AT still does.
388
+ data.merge!(data_for_update_columns)
389
+
390
+ versions_assoc = @record.send(@record.class.versions_association_name)
391
+ version = versions_assoc.new(data)
392
+ begin
393
+ version.save!
394
+
395
+ if version && version.respond_to?(:errors) && version.errors.empty?
396
+ update_transaction_id(version)
397
+ end
398
+
399
+ version
400
+ rescue StandardError => e
401
+ handle_version_errors e, version, :update
359
402
  end
360
-
361
- version
362
- rescue StandardError => e
363
- handle_version_errors e, version, :update
364
403
  end
365
- end
366
404
 
367
- def version
368
- @record.public_send(@record.class.version_association_name)
369
- end
405
+ def version
406
+ @record.public_send(@record.class.version_association_name)
407
+ end
370
408
 
371
- def versions
372
- @record.public_send(@record.class.versions_association_name)
373
- end
409
+ def versions
410
+ @record.public_send(@record.class.versions_association_name)
411
+ end
374
412
  end
375
413
  end
@@ -57,7 +57,7 @@ module SnailTrail
57
57
  # The `dup` option and destroyed version always returns a new object,
58
58
  # otherwise we should attempt to load item or to look for the item
59
59
  # outside of default scope(s).
60
- model = if options[:dup] == true || version.event == "destroy"
60
+ model = if options[:dup] == true || version.event == "destroy" || version.event == "batch_destroy"
61
61
  klass.new
62
62
  else
63
63
  version.item || init_model_by_finding_item_id(klass, version) || klass.new
@@ -3,7 +3,7 @@
3
3
  require "request_store"
4
4
 
5
5
  module SnailTrail
6
- # Manages variables that affect the current HTTP request, such as `whodunnit`.
6
+ # Manages variables that affect the current HTTP request, such as `whodunnit` and `performance_mode`.
7
7
  #
8
8
  # Please do not use `SnailTrail::Request` directly, use `SnailTrail.request`.
9
9
  # Currently, `Request` is a `Module`, but in the future it is quite possible
@@ -96,7 +96,7 @@ module SnailTrail
96
96
  return unless block_given?
97
97
  validate_public_options(options)
98
98
  before = to_h
99
- merge(options)
99
+ merge({ performance_mode: false, performance_mode_data: nil }.merge(options))
100
100
  yield
101
101
  ensure
102
102
  set(before)
@@ -124,57 +124,91 @@ module SnailTrail
124
124
  who.respond_to?(:call) ? who.call : who
125
125
  end
126
126
 
127
- private
127
+ # Enables performance mode for this request
128
+ def performance_mode!
129
+ self.performance_mode = true
130
+ end
128
131
 
129
- # @api private
130
- def merge(options)
131
- options.to_h.each do |k, v|
132
- store[k] = v
133
- end
132
+ def clear_performance_mode
133
+ self.performance_mode = false
134
+ self.performance_mode_data = nil
134
135
  end
135
136
 
136
- # @api private
137
- def set(options)
138
- store.clear
139
- merge(options)
137
+ def performance_mode= val
138
+ store[:performance_mode] = !!val
139
+
140
+ if performance_mode?
141
+ self.performance_mode_data = []
142
+ end
143
+
144
+ performance_mode?
140
145
  end
141
146
 
142
- # Returns a Hash, initializing with default values if necessary.
143
- # @api private
144
- def store
145
- RequestStore.store[:snail_trail] ||= {
146
- enabled: true
147
- }
147
+ # Returns whether or not performance mode is enabled for this request
148
+ # Default: disabled
149
+ #
150
+ # @api public
151
+ #
152
+ def performance_mode?
153
+ !!store[:performance_mode]
148
154
  end
149
155
 
150
- # Returns a deep copy of the internal hash from our RequestStore. Keys are
151
- # all symbols. Values are mostly primitives, but whodunnit can be a Proc.
152
- # We cannot use Marshal.dump here because it doesn't support Proc. It is
153
- # unclear exactly how `deep_dup` handles a Proc, but it doesn't complain.
154
- # @api private
155
- def to_h
156
- store.deep_dup
156
+ def performance_mode_data
157
+ store[:performance_mode_data]
157
158
  end
158
159
 
159
- # Provide a helpful error message if someone has a typo in one of their
160
- # option keys. We don't validate option values here. That's traditionally
161
- # been handled with casting (`to_s`, `!!`) in the accessor method.
162
- # @api private
163
- def validate_public_options(options)
164
- options.each do |k, _v|
165
- case k
166
- when :controller_info,
167
- /enabled_for_/,
168
- :enabled,
169
- :whodunnit
170
- next
171
- when :transaction_id
172
- raise ::SnailTrail::Request::InvalidOption, "Cannot set private option: transaction_id"
173
- else
174
- raise InvalidOption, "Invalid option: #{k}"
160
+ private
161
+
162
+ def performance_mode_data= val
163
+ store[:performance_mode_data] = val
164
+ end
165
+
166
+ # @api private
167
+ def merge(options)
168
+ options.to_h.each do |k, v|
169
+ store[k] = v
170
+ end
171
+ end
172
+
173
+ # @api private
174
+ def set(options)
175
+ store.clear
176
+ merge(options)
177
+ end
178
+
179
+ # Returns a Hash, initializing with default values if necessary.
180
+ # @api private
181
+ def store
182
+ RequestStore.store[:snail_trail] ||= {
183
+ enabled: true
184
+ }
185
+ end
186
+
187
+ # Returns a deep copy of the internal hash from our RequestStore. Keys are
188
+ # all symbols. Values are mostly primitives, but whodunnit can be a Proc.
189
+ # We cannot use Marshal.dump here because it doesn't support Proc. It is
190
+ # unclear exactly how `deep_dup` handles a Proc, but it doesn't complain.
191
+ # @api private
192
+ def to_h
193
+ store.deep_dup
194
+ end
195
+
196
+ # Provide a helpful error message if someone has a typo in one of their
197
+ # option keys. We don't validate option values here. That's traditionally
198
+ # been handled with casting (`to_s`, `!!`) in the accessor method.
199
+ # @api private
200
+ def validate_public_options(options)
201
+ options.each do |k, _v|
202
+ case k
203
+ when :controller_info, /enabled_for_/, :enabled, :whodunnit, :performance_mode, :performance_mode_data
204
+ next
205
+ when :transaction_id
206
+ raise ::SnailTrail::InvalidOption, "Cannot set private option: transaction_id"
207
+ else
208
+ raise InvalidOption, "Invalid option: #{k}"
209
+ end
175
210
  end
176
211
  end
177
- end
178
212
  end
179
213
  end
180
214
  end
@@ -35,15 +35,15 @@ module SnailTrail
35
35
  end
36
36
 
37
37
  def creates
38
- where event: "create"
38
+ where event: %w[create batch_create]
39
39
  end
40
40
 
41
41
  def updates
42
- where event: "update"
42
+ where event: %w[update batch_update]
43
43
  end
44
44
 
45
45
  def destroys
46
- where event: "destroy"
46
+ where event: %w[destroy batch_destroy]
47
47
  end
48
48
 
49
49
  def not_creates
@@ -8,11 +8,11 @@ module SnailTrail
8
8
  # People are encouraged to use `SnailTrail.gem_version` instead.
9
9
  module VERSION
10
10
  MAJOR = 1
11
- MINOR = 0
11
+ MINOR = 1
12
12
  TINY = 0
13
13
 
14
14
  # Set PRE to nil unless it's a pre-release (beta, rc, etc.)
15
- PRE = nil
15
+ PRE = 'rc.pre.1'
16
16
 
17
17
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".").freeze
18
18
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: snail_trail
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.0.rc.pre.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brands Insurance
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-05-09 00:00:00.000000000 Z
11
+ date: 2025-05-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -411,9 +411,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
411
411
  version: 3.2.0
412
412
  required_rubygems_version: !ruby/object:Gem::Requirement
413
413
  requirements:
414
- - - ">="
414
+ - - ">"
415
415
  - !ruby/object:Gem::Version
416
- version: '0'
416
+ version: 1.3.1
417
417
  requirements: []
418
418
  rubygems_version: 3.4.10
419
419
  signing_key: