# encoding: utf-8
module Mongoid #:nodoc:
module Associations #:nodoc:
# Represents an relational one-to-many association with an object in a
# separate collection or database, stored as an array of ids on the parent
# document.
class ReferencesManyAsArray < ReferencesMany
# Append a document to this association. This will also set the appended
# document's id on the inverse association as well.
#
# Example:
#
# person.preferences << Preference.new(:name => "VGA")
def <<(*objects)
@target = @target.entries
objects.flatten.each do |object|
# First set the documents id on the parent array of ids.
@parent.send(@foreign_key) << object.id
# Then we need to set the parent's id on the documents array of ids
# to get the inverse side of the association as well. Note, need a
# clean way to handle this with new documents - we want to set the
# actual objects as well, but dont want to get in an infinite loop
# while doing so.
if inverse?
reverse_key = reverse_key(object)
case inverse_of(object).macro
when :references_many
object.send(reverse_key) << @parent.id
when :referenced_in
object.send("#{reverse_key}=", @parent.id)
end
end
@target << object
end
end
alias :concat :<<
alias :push :<<
# Builds a new Document and adds it to the association collection. The
# document created will be of the same class as the others in the
# association, and the attributes will be passed into the constructor.
#
# Returns the newly created object.
def build(attributes = nil)
load_target
document = @klass.instantiate(attributes || {})
push(document); document
end
protected
# Find the inverse key for the supplied document.
def reverse_key(document)
inverse_of(document).options.foreign_key
end
# Returns +true+ if there is an inverse association on the referenced
# model.
def inverse?
!!@options.inverse_of
end
# Returns the association on +document+ which is the inverse of this
# association.
def inverse_of(document)
document.class.associations[@options.inverse_of.to_s]
end
# The default query used for retrieving the documents from the database.
def query
@query ||= lambda { @klass.any_in(:_id => @parent.send(@foreign_key)) }
end
class << self
# Perform an update of the relationship of the parent and child. This
# will assimilate the child +Document+ into the parent's object graph.
#
# Options:
#
# related: The related object
# parent: The parent +Document+ to update.
# options: The association +Options+
#
# Example:
#
# RelatesToManyAsArray.update(preferences, person, options)
def update(target, document, options)
target.each do |child|
document.send(options.name) << child
end
instantiate(document, options, target)
end
end
end
end
end