class ActiveFedora::Associations::Association


HasManyAssociation
AssociationCollection
BelongsToAssociation
Association
This is the root class of all associations:

def association_scope

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

The scope for this association.
def association_scope
  if klass
    @association_scope ||= AssociationScope.new(self).scope
  end
end

def build_record(attributes)

def build_record(attributes)
  # TODO make initalize take a block and get rid of the tap
  reflection.build_association(attributes).tap do |record|
    initialize_attributes(record)
  end
end

def find_target?

def find_target?
  !loaded? && (!owner.new_record? || foreign_key_present?) && klass
end

def foreign_key_present?

Currently implemented by belongs_to

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

def initialize(owner, reflection)

def initialize(owner, reflection)
  reflection.check_validity!
  @owner, @reflection = owner, reflection
  reset
  # construct_scope
end

def initialize_attributes(record) #:nodoc:

:nodoc:
def initialize_attributes(record) #:nodoc:
  skip_assign = [reflection.foreign_key].compact
  attributes = create_scope.except(*(record.changed - skip_assign))
  record.attributes = attributes
  set_inverse_instance(record)
end

def inverse_reflection_for(record)

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

def invertible_for?(record)

This method is redefined by subclasses.
Returns true if inverse association on the given record needs to be set.
def invertible_for?(record)
  inverse_reflection_for(record)
end

def load_target

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

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

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

Loads the \target if needed and returns it.
def load_target
  @target = find_target if (@stale_state && stale_target?) || find_target?
  loaded! unless loaded?
  target
end

def loaded!

Asserts the \target has been loaded setting the \loaded flag to +true+.
def loaded!
  @loaded = true
  @stale_state = stale_state
  @inversed = false
end

def loaded?

Has the \target been already \loaded?
def loaded?
  @loaded
end

def raise_on_type_mismatch(record)

a sanity check when you are about to assign an associated record.
the kind of the class of the associated objects. Meant to be used as
Raises ActiveFedora::AssociationTypeMismatch unless +record+ is of
def raise_on_type_mismatch(record)
  unless record.is_a?(@reflection.klass) || record.is_a?(@reflection.class_name.constantize)
    message = "#{@reflection.class_name}(##{@reflection.klass.object_id}) expected, got #{record.class}(##{record.class.object_id})"
    raise ActiveFedora::AssociationTypeMismatch, message
  end
end

def reload

Reloads the \target and returns +self+ on success.
def reload
  reset
  # construct_scope
  load_target
  self unless @target.nil?
end

def reset

Resets the \loaded flag to +false+ and sets the \target to +nil+.
def reset
  @loaded = false
  @target = nil
  @inversed = false
end

def scope

def scope
  target_scope.merge(association_scope)
end

def set_inverse_instance(record)

Set the inverse association, if possible
def set_inverse_instance(record)
  if 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
end

def stale_state

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

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

def stale_target?

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

state_state method if relevant.
on the owner will reload the target. It's up to subclasses to implement the
relevant foreign_key(s) refers to. If stale, the association accessor method
The target is stale if the target no longer points to the record(s) that the
def stale_target?
  !inversed && loaded? && @stale_state != stale_state
end

def target=(target)

Sets the target of this proxy to \target, and the \loaded flag to +true+.
def target=(target)
  @target = target
  loaded!
end

def target_scope

through association's scope)
Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the
def target_scope
  klass.all
end