class ActiveFedora::Associations::Association

This is the root class of all associations:

Association
  BelongsToAssociation
  AssociationCollection
    HasManyAssociation

Attributes

inversed[RW]
owner[R]
reflection[R]
target[R]

Public Class Methods

new(owner, reflection) click to toggle source
# File lib/active_fedora/associations/association.rb, line 16
def initialize(owner, reflection)
  reflection.check_validity!
  @owner = owner
  @reflection = reflection
  reset
  reset_scope
end

Public Instance Methods

association_scope() click to toggle source

The scope for this association.

Note that the association_scope is merged into the target_scope only when the scope method is called. This is because at that point the call may be surrounded by scope.scoping { … } or with_scope { … } etc, which affects the scope which actually gets built.

# File lib/active_fedora/associations/association.rb, line 78
def association_scope
  @association_scope ||= AssociationScope.scope(self) if klass
end
load_target() click to toggle source

Loads the target if needed and returns it.

This method is abstract in the sense that it relies on find_target, which is expected to be provided by descendants.

If the target is already loaded it is just returned. Thus, you can call load_target unconditionally to get the target.

ActiveFedora::ObjectNotFoundError is rescued within the method, and it is not reraised. The proxy is reset and nil is the return value.

# File lib/active_fedora/associations/association.rb, line 114
def load_target
  @target = find_target if (@stale_state && stale_target?) || find_target?
  loaded! unless loaded?
  target
rescue ActiveFedora::ObjectNotFoundError
  reset
end
loaded!() click to toggle source

Asserts the target has been loaded setting the loaded flag to true.

# File lib/active_fedora/associations/association.rb, line 46
def loaded!
  @loaded = true
  @stale_state = stale_state
  @inversed = false
end
loaded?() click to toggle source

Has the target been already loaded?

# File lib/active_fedora/associations/association.rb, line 41
def loaded?
  @loaded
end
reload() click to toggle source

Reloads the target and returns self on success.

# File lib/active_fedora/associations/association.rb, line 33
def reload
  reset
  reset_scope
  load_target
  self unless @target.nil?
end
reset() click to toggle source

Resets the loaded flag to false and sets the target to nil.

# File lib/active_fedora/associations/association.rb, line 25
def reset
  @loaded = false
  @target = nil
  @stale_state = nil
  @inversed = false
end
reset_scope() click to toggle source
# File lib/active_fedora/associations/association.rb, line 82
def reset_scope
  @association_scope = nil
end
scope() click to toggle source
# File lib/active_fedora/associations/association.rb, line 68
def scope
  target_scope.merge(association_scope)
end
set_inverse_instance(record) click to toggle source

Set the inverse association, if possible

# File lib/active_fedora/associations/association.rb, line 87
def set_inverse_instance(record)
  return unless record && invertible_for?(record)
  inverse = record.association(inverse_reflection_for(record).name.to_sym)
  if inverse.is_a? ActiveFedora::Associations::HasAndBelongsToManyAssociation
    inverse.target << owner
  else
    inverse.target = owner
  end
  inverse.inversed = true
end
stale_target?() click to toggle source

The target is stale if the target no longer points to the record(s) that the relevant foreign_key(s) refers to. If stale, the association accessor method on the owner will reload the target. It’s up to subclasses to implement the state_state method if relevant.

Note that if the target has not been loaded, it is not considered stale.

# File lib/active_fedora/associations/association.rb, line 58
def stale_target?
  !inversed && loaded? && @stale_state != stale_state
end
target=(target) click to toggle source

Sets the target of this proxy to \target, and the loaded flag to true.

# File lib/active_fedora/associations/association.rb, line 63
def target=(target)
  @target = target
  loaded!
end
target_scope() click to toggle source

Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the through association’s scope)

# File lib/active_fedora/associations/association.rb, line 100
def target_scope
  klass.all
end

Private Instance Methods

build_record(attributes) click to toggle source
# File lib/active_fedora/associations/association.rb, line 205
def build_record(attributes)
  reflection.build_association(attributes) do |record|
    initialize_attributes(record)
  end
end
creation_attributes() click to toggle source
# File lib/active_fedora/associations/association.rb, line 138
def creation_attributes
  attributes = {}

  if (reflection.has_one? || reflection.collection?) && !options[:through]
    attributes[reflection.foreign_key] = owner[reflection.active_record_primary_key]

    attributes[reflection.type] = owner.class.base_class.name if reflection.options[:as]
  end

  attributes
end
find_target?() click to toggle source
# File lib/active_fedora/associations/association.rb, line 134
def find_target?
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
end
foreign_key_present?() click to toggle source

Returns true if there is a foreign key present on the owner which references the target. This is used to determine whether we can load the target if the owner is currently a new record (and therefore without a key). If the owner is a new record then foreign_key must be present in order to load target.

Currently implemented by belongs_to

# File lib/active_fedora/associations/association.rb, line 162
def foreign_key_present?
  false
end
inverse_reflection_for(_record) click to toggle source

Can be redefined by subclasses, notably polymorphic belongs_to The record parameter is necessary to support polymorphic inverses as we must check for the association in the specific class of the record.

# File lib/active_fedora/associations/association.rb, line 188
def inverse_reflection_for(_record)
  reflection.inverse_of
end
invertible_for?(record) click to toggle source

Returns true if inverse association on the given record needs to be set. This method is redefined by subclasses.

# File lib/active_fedora/associations/association.rb, line 194
def invertible_for?(record)
  inverse_reflection_for(record)
end
raise_on_type_mismatch!(record) click to toggle source

Raises ActiveFedora::AssociationTypeMismatch unless record is of the kind of the class of the associated objects. Meant to be used as a sanity check when you are about to assign an associated record.

# File lib/active_fedora/associations/association.rb, line 169
def raise_on_type_mismatch!(record)
  unless record.is_a?(reflection.klass)
    fresh_class = reflection.class_name.safe_constantize
    unless fresh_class && record.is_a?(fresh_class)
      message = "#{reflection.class_name}(##{reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
      raise ActiveFedora::AssociationTypeMismatch, message
    end
  end

  type_validator.validate!(self, record)
end
set_owner_attributes(record) click to toggle source

Sets the owner attributes on the given record

# File lib/active_fedora/associations/association.rb, line 151
def set_owner_attributes(record)
  creation_attributes.each { |key, value| record[key] = value }
end
stale_state() click to toggle source

This should be implemented to return the values of the relevant key(s) on the owner, so that when state_state is different from the value stored on the last find_target, the target is stale.

This is only relevant to certain associations, which is why it returns nil by default.

# File lib/active_fedora/associations/association.rb, line 203
def stale_state; end
type_validator() click to toggle source
# File lib/active_fedora/associations/association.rb, line 181
def type_validator
  options[:type_validator] || NullValidator
end