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



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

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



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

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!(validate: false)
    # NOTE: after_instance always exists
    after_instance.save!(validate: false)

    # 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

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

#destroy(force_delete: false) ⇒ Object



335
336
337
338
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
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 335

def destroy(force_delete: false)
  return super() if force_delete

  current_time = Time.current
  target_datetime = valid_datetime || current_time

  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(current_time)

      # 削除時の状態を履歴レコードとして保存する
      duplicated_instance.valid_to = target_datetime
      duplicated_instance.transaction_from = current_time
      duplicated_instance.save!(validate: false)
      if @destroyed
        @_swapped_id_previously_was = swapped_id
        @_swapped_id = duplicated_instance.swapped_id
      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

#save ⇒ Object



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

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



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

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