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



289
290
291
292
293
294
295
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 289

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



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

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 = 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



331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 331

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)
      @_swapped_id = duplicated_instance.swapped_id if @destroyed
    }
    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



297
298
299
300
301
302
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 297

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



304
305
306
307
308
309
# File 'lib/activerecord-bitemporal/bitemporal.rb', line 304

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