module PaperTrailAssociationTracking::Reifiers::HasOne

Reify a single `has_one` association of `model`. @api private

Public Class Methods

reify(assoc, model, options, transaction_id) click to toggle source

@api private

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 42
def reify(assoc, model, options, transaction_id)
  version = load_version(assoc, model, transaction_id, options[:version_at])
  return unless version
  if version.event == "create"
    create_event(assoc, model, options)
  else
    noncreate_event(assoc, model, options, version)
  end
end

Private Class Methods

create_event(assoc, model, options) click to toggle source

@api private

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 55
def create_event(assoc, model, options)
  if options[:mark_for_destruction]
    model.send(assoc.name).mark_for_destruction if model.send(assoc.name, true)
  else
    model.paper_trail.appear_as_new_record do
      model.send "#{assoc.name}=", nil
    end
  end
end
load_version(assoc, model, transaction_id, version_at) click to toggle source

Given a has-one association `assoc` on `model`, return the version record from the point in time identified by `transaction_id` or `version_at`. @api private

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 68
def load_version(assoc, model, transaction_id, version_at)
  base_class_name = assoc.klass.base_class.name
  versions = load_versions(assoc, model, transaction_id, version_at, base_class_name)
  case versions.length
  when 0
    nil
  when 1
    versions.first
  else
    case ::PaperTrail.config.association_reify_error_behaviour
    when "warn"
      version = versions.first
      version.logger&.warn(
        FoundMoreThanOne.new(base_class_name, versions.length).message
      )
      version
    when "ignore"
      versions.first
    else # "error"
      raise FoundMoreThanOne.new(base_class_name, versions.length)
    end
  end
end
load_versions(assoc, model, transaction_id, version_at, base_class_name) click to toggle source

@api private

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 93
def load_versions(assoc, model, transaction_id, version_at, base_class_name)
  version_table_name = model.class.paper_trail.version_class.table_name
  model.class.paper_trail.version_class.joins(:version_associations).
    where("version_associations.foreign_key_name = ?", assoc.foreign_key).
    where("version_associations.foreign_key_id = ?", model.id).
    where("#{version_table_name}.item_type = ?", base_class_name).
    where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
    order("#{version_table_name}.id ASC").
    load
end
noncreate_event(assoc, model, options, version) click to toggle source

@api private

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 105
def noncreate_event(assoc, model, options, version)
  child = version.reify(
    options.merge(
      has_many: false,
      has_one: false,
      belongs_to: false,
      has_and_belongs_to_many: false
    )
  )
  model.paper_trail.appear_as_new_record do
    without_persisting(child) do
      model.send "#{assoc.name}=", child
    end
  end
end
without_persisting(record) { || ... } click to toggle source

Temporarily suppress save so we can reassociate with the reified master of a has_one relationship. Since ActiveRecord 5 the related object is saved when it is assigned to the association. ActiveRecord 5 also happens to be the first version that provides suppress.

# File lib/paper_trail_association_tracking/reifiers/has_one.rb, line 125
def without_persisting(record)
  if record.class.respond_to? :suppress
    record.class.suppress { yield }
  else
    yield
  end
end