Module: ActiveRecord::Bitemporal::Persistence

Includes:
PersistenceOptionable
Included in:
Bitemporalize::InstanceMethods
Defined in:
lib/activerecord-bitemporal/bitemporal.rb

Overview

create, update, destroy に処理をフックする

Defined Under Namespace

Modules: EachAssociation, PersistenceOptionable

Instance Method Summary collapse

Methods included from PersistenceOptionable

#bitemporal_option_merge_with_association!, #force_update, #force_update?, #transaction_at, #transaction_datetime, #valid_at, #valid_datetime

Methods included from Optionable

#bitemporal_option, #bitemporal_option_merge!, #with_bitemporal_option

Instance Method Details

#_create_record(attribute_names = self.attribute_names) ⇒ Object



293
294
295
296
297
298
299
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 293

def _create_record(attribute_names = self.attribute_names)
  bitemporal_assign_initialize_value(valid_datetime: self.valid_datetime)

  ActiveRecord::Bitemporal.valid_at!(self.valid_from) {
    super()
  }
end

#_update_row(attribute_names, attempted_action = 'update') ⇒ Object



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 315

def _update_row(attribute_names, attempted_action = 'update')
  current_valid_record, before_instance, after_instance = bitemporal_build_update_records(valid_datetime: self.valid_datetime, force_update: self.force_update?)

  # MEMO: このメソッドに来るまでに validation が発動しているので、以後 validate は考慮しなくて大丈夫
  ActiveRecord::Base.transaction(requires_new: true) do
    current_valid_record&.update_transaction_to(current_valid_record.transaction_to)
    before_instance&.save_without_bitemporal_callbacks!(validate: false)
    # NOTE: after_instance always exists
    after_instance.save_without_bitemporal_callbacks!(validate: false)
    @previously_force_updated = self.force_update?

    # update 後に新しく生成したインスタンスのデータを移行する
    @_swapped_id_previously_was = swapped_id
    @_swapped_id = after_instance.swapped_id
    self.valid_from = after_instance.valid_from
    self.valid_to = after_instance.valid_to
    self.transaction_from = after_instance.transaction_from
    self.transaction_to = after_instance.transaction_to

    1
  # MEMO: Must return false instead of nil, if `#_update_row` failure.
  end || false
end

#destroy(force_delete: false, operated_at: Time.current) ⇒ Object



339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 339

def destroy(force_delete: false, operated_at: Time.current)
  return super() if force_delete

  target_datetime = valid_datetime || operated_at

  duplicated_instance = self.class.find_at_time(target_datetime, self.id).dup

  ActiveRecord::Base.transaction(requires_new: true, joinable: false) do
    @destroyed = false
    _run_destroy_callbacks {
      @destroyed = update_transaction_to(operated_at)
      @previously_force_updated = force_update?

      # force_update の場合は削除時の状態の履歴を残さない
      unless force_update?
        # 削除時の状態を履歴レコードとして保存する
        duplicated_instance.valid_to = target_datetime
        duplicated_instance.transaction_from = operated_at
        duplicated_instance.save_without_bitemporal_callbacks!(validate: false)
        if @destroyed
          @_swapped_id_previously_was = swapped_id
          @_swapped_id = duplicated_instance.swapped_id
          self.valid_from = duplicated_instance.valid_from
          self.valid_to = duplicated_instance.valid_to
          self.transaction_from = duplicated_instance.transaction_from
          self.transaction_to = duplicated_instance.transaction_to
        end
      end
    }
    raise ActiveRecord::RecordInvalid unless @destroyed

    self
  end
rescue => e
  @destroyed = false
  @_association_destroy_exception = ActiveRecord::RecordNotDestroyed.new("Failed to destroy the record: class=#{e.class}, message=#{e.message}", self)
  false
end

#saveObject



301
302
303
304
305
306
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 301

def save(**)
  ActiveRecord::Base.transaction(requires_new: true) do
    self.class.where(bitemporal_id: self.id).lock!.pluck(:id) if self.id
    super
  end
end

#save!Object



308
309
310
311
312
313
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 308

def save!(**)
  ActiveRecord::Base.transaction(requires_new: true) do
    self.class.where(bitemporal_id: self.id).lock!.pluck(:id) if self.id
    super
  end
end