module Mongoid::Association::Bindable

Superclass for all objects that bind associations together.

Attributes

_association[R]
_base[R]
_target[R]

Public Class Methods

new(base, target, association) click to toggle source

Create the new binding.

@example Initialize a binding.

Binding.new(base, target, association)

@param [ Document ] base The base of the binding. @param [ Document | Array<Document> ] target The target of the binding. @param [ Mongoid::Association::Relatable ] association The association metadata.

# File lib/mongoid/association/bindable.rb, line 21
def initialize(base, target, association)
  @_base, @_target, @_association = base, target, association
end

Public Instance Methods

binding() { |self| ... } click to toggle source

Execute the provided block inside a binding.

@example Execute the binding block.

binding.binding do
  base.foreign_key = 1
end

@return [ Object ] The result of the yield.

# File lib/mongoid/association/bindable.rb, line 33
def binding
  unless _binding?
    _binding do
      yield(self) if block_given?
    end
  end
end

Private Instance Methods

bind_foreign_key(keyed, id) click to toggle source

Set the id of the related document in the foreign key field on the keyed document.

@api private

@example Bind the foreign key.

binding.bind_foreign_key(post, person._id)

@param [ Document ] keyed The document that stores the foreign key. @param [ Object ] id The id of the bound document.

# File lib/mongoid/association/bindable.rb, line 121
def bind_foreign_key(keyed, id)
  unless keyed.frozen?
    try_method(keyed, _association.foreign_key_setter, id)
  end
end
bind_from_relational_parent(doc) click to toggle source

Bind the provided document with the base from the parent association.

@api private

@example Bind the document with the base.

binding.bind_from_relational_parent(doc)

@param [ Document ] doc The document to bind.

# File lib/mongoid/association/bindable.rb, line 183
def bind_from_relational_parent(doc)
  check_inverse!(doc)
  remove_associated(doc)
  bind_foreign_key(doc, record_id(_base))
  bind_polymorphic_type(doc, _base.class.name)
  bind_inverse(doc, _base)
end
bind_inverse(doc, inverse) click to toggle source

Bind the inverse document to the child document so that the in memory instances are the same.

@api private

@example Bind the inverse.

binding.bind_inverse(post, person)

@param [ Document ] doc The base document. @param [ Document ] inverse The inverse document.

# File lib/mongoid/association/bindable.rb, line 169
def bind_inverse(doc, inverse)
  if doc.respond_to?(_association.inverse_setter) && !doc.frozen?
    try_method(doc, _association.inverse_setter, inverse)
  end
end
bind_polymorphic_inverse_type(typed, name) click to toggle source

Set the type of the related document on the foreign type field, used when associations are polymorphic.

@api private

@example Bind the polymorphic type.

binding.bind_polymorphic_inverse_type(post, "Person")

@param [ Document ] typed The document that stores the type field. @param [ String ] name The name of the model.

# File lib/mongoid/association/bindable.rb, line 153
def bind_polymorphic_inverse_type(typed, name)
  if _association.inverse_type && !typed.frozen?
    try_method(typed, _association.inverse_type_setter, name)
  end
end
bind_polymorphic_type(typed, name) click to toggle source

Set the type of the related document on the foreign type field, used when associations are polymorphic.

@api private

@example Bind the polymorphic type.

binding.bind_polymorphic_type(post, "Person")

@param [ Document ] typed The document that stores the type field. @param [ String ] name The name of the model.

# File lib/mongoid/association/bindable.rb, line 137
def bind_polymorphic_type(typed, name)
  if _association.type && !typed.frozen?
    try_method(typed, _association.type_setter, name)
  end
end
check_inverse!(doc) click to toggle source

Check if the inverse is properly defined.

@api private

@example Check the inverse definition.

binding.check_inverse!(doc)

@param [ Document ] doc The document getting bound.

@raise [ Errors::InverseNotFound ] If no inverse found.

# File lib/mongoid/association/bindable.rb, line 53
def check_inverse!(doc)
  unless _association.bindable?(doc)
    raise Errors::InverseNotFound.new(
        _base.class,
        _association.name,
        doc.class,
        _association.foreign_key
    )
  end
end
record_id(_base) click to toggle source
# File lib/mongoid/association/bindable.rb, line 191
def record_id(_base)
  _base.__send__(_association.primary_key)
end
remove_associated(doc) click to toggle source

Remove the associated document from the inverse’s association.

@param [ Document ] doc The document to remove.

# File lib/mongoid/association/bindable.rb, line 67
def remove_associated(doc)
  if inverse = _association.inverse(doc)
    if _association.many?
      remove_associated_many(doc, inverse)
    elsif _association.in_to?
      remove_associated_in_to(doc, inverse)
    end
  end
end
remove_associated_in_to(doc, inverse) click to toggle source

Remove the associated document from the inverse’s association.

This method removes associated on belongs_to and embedded_in associations.

@param [ Document ] doc The document to remove. @param [ Symbol ] inverse The name of the inverse.

# File lib/mongoid/association/bindable.rb, line 103
def remove_associated_in_to(doc, inverse)
  # We only want to remove the inverse association when the inverse
  # document is in memory.
  if associated = doc.ivar(inverse)
    associated.send(_association.setter, nil)
  end
end
remove_associated_many(doc, inverse) click to toggle source

Remove the associated document from the inverse’s association.

This method removes the associated on *_many relationships.

@param [ Document ] doc The document to remove. @param [ Symbol ] inverse The name of the inverse.

# File lib/mongoid/association/bindable.rb, line 83
def remove_associated_many(doc, inverse)
  # We only want to remove the inverse association when the inverse
  # document is in memory.
  if inv = doc.ivar(inverse)
    # This first condition is needed because when assigning the
    # embeds_many association using the same embeds_many
    # association, we delete from the array we are about to assign.
    if _base != inv && (associated = inv.ivar(_association.name))
      associated.delete(doc)
    end
  end
end
set_base_association() click to toggle source

Ensure that the association on the base is correct, for the cases where we have multiple belongs to definitions and were are setting different parents in memory in order.

@api private

@example Set the base association.

binding.set_base_association

@return [ true | false ] If the association changed.

# File lib/mongoid/association/bindable.rb, line 205
def set_base_association
  inverse_association = _association.inverse_association(_target)
  if inverse_association != _association && !inverse_association.nil?
    _base._association = inverse_association
  end
end
try_method(object, method_name, *args) click to toggle source

Convenience method to perform #try but return nil if the method argument is nil.

@example Call method if it exists.

object.try_method(:use, "The Force")

@example Return nil if method argument is nil.

object.try_method(nil, "The Force") #=> nil

@param [ String | Symbol ] method_name The method name. @param [ Object… ] *args The arguments.

@return [ Object | nil ] The result of the try or nil if the

method does not exist.
# File lib/mongoid/association/bindable.rb, line 241
def try_method(object, method_name, *args)
  object.try(method_name, *args) if method_name
end
unbind_from_relational_parent(doc) click to toggle source

Bind the provided document with the base from the parent association.

@api private

@example Bind the document with the base.

unbinding.unbind_from_relational_parent(doc)

@param [ Document ] doc The document to unbind.

# File lib/mongoid/association/bindable.rb, line 220
def unbind_from_relational_parent(doc)
  check_inverse!(doc)
  bind_foreign_key(doc, nil)
  bind_polymorphic_type(doc, nil)
  bind_inverse(doc, nil)
end