class Mongoid::Relations::Builders::NestedAttributes::Many

Public Class Methods

new(metadata, attributes, options = {}) click to toggle source

Create the new builder for nested attributes on one-to-many relations.

@example Initialize the builder.

One.new(metadata, attributes, options)

@param [ Metadata ] metadata The relation metadata. @param [ Hash ] attributes The attributes hash to attempt to set. @param [ Hash ] options The options defined.

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 44
def initialize(metadata, attributes, options = {})
  if attributes.respond_to?(:with_indifferent_access)
    @attributes = attributes.with_indifferent_access.sort do |a, b|
      a[0].to_i <=> b[0].to_i
    end
  else
    @attributes = attributes
  end
  @metadata = metadata
  @options = options
end

Public Instance Methods

build(parent, options = {}) click to toggle source

Builds the relation depending on the attributes and the options passed to the macro.

This attempts to perform 3 operations, either one of an update of the existing relation, a replacement of the relation with a new document, or a removal of the relation.

@example Build the nested attrs.

many.build(person)

@param [ Document ] parent The parent document of the relation.

@return [ Array ] The attributes.

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 21
def build(parent, options = {})
  @existing = parent.send(metadata.name)
  if over_limit?(attributes)
    raise Errors::TooManyNestedAttributeRecords.new(existing, options[:limit])
  end
  attributes.each do |attrs|
    if attrs.is_a?(::Hash)
      process_attributes(parent, attrs.with_indifferent_access)
    else
      process_attributes(parent, attrs[1].with_indifferent_access)
    end
  end
end

Private Instance Methods

destroy(parent, relation, doc) click to toggle source

Destroy the child document, needs to do some checking for embedded relations and delay the destroy in case parent validation fails.

@api private

@example Destroy the child.

builder.destroy(parent, relation, doc)

@param [ Document ] parent The parent document. @param [ Proxy ] relation The relation proxy. @param [ Document ] doc The doc to destroy.

@since 3.0.10

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 126
def destroy(parent, relation, doc)
  doc.flagged_for_destroy = true
  if !doc.embedded? || parent.new_record?
    destroy_document(relation, doc)
  else
    parent.flagged_destroys.push(->{ destroy_document(relation, doc) })
  end
end
destroy_document(relation, doc) click to toggle source

Destroy the document.

@api private

@example Destroy the document.

builder.destroy_document(relation, doc)

@param [ Proxy ] relation The relation proxy. @param [ Document ] doc The document to delete.

@since 3.0.10

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 146
def destroy_document(relation, doc)
  relation.delete(doc)
  doc.destroy unless doc.embedded? || doc.destroyed?
end
destroyable?(attributes) click to toggle source

Can the existing relation potentially be deleted?

@example Is the document destroyable?

destroyable?({ :_destroy => "1" })

@parma [ Hash ] attributes The attributes to pull the flag from.

@return [ true, false ] If the relation can potentially be deleted.

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 66
def destroyable?(attributes)
  destroy = attributes.delete(:_destroy)
  [ 1, "1", true, "true" ].include?(destroy) && allow_destroy?
end
over_limit?(attributes) click to toggle source

Are the supplied attributes of greater number than the supplied limit?

@example Are we over the set limit?

builder.over_limit?({ "street" => "Bond" })

@param [ Hash ] attributes The attributes being set.

@return [ true, false ] If the attributes exceed the limit.

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 80
def over_limit?(attributes)
  limit = options[:limit]
  limit ? attributes.size > limit : false
end
process_attributes(parent, attrs) click to toggle source

Process each set of attributes one at a time for each potential new, existing, or ignored document.

@api private

@example Process the attributes

builder.process_attributes({ "id" => 1, "street" => "Bond" })

@param [ Document ] parent The parent document. @param [ Hash ] attrs The single document attributes to process.

@since 2.0.0

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 97
def process_attributes(parent, attrs)
  return if reject?(parent, attrs)
  if id = attrs.extract_id
    first = existing.first
    converted = first ? convert_id(first.class, id) : id
    doc = existing.find(converted)
    if destroyable?(attrs)
      destroy(parent, existing, doc)
    else
      update_document(doc, attrs)
    end
  else
    existing.push(Factory.build(metadata.klass, attrs)) unless destroyable?(attrs)
  end
end
update_document(doc, attrs) click to toggle source

Update the document.

@api private

@example Update the document.

builder.update_document(doc, {}, options)

@param [ Document ] doc The document to update. @param [ Hash ] attrs The attributes.

@since 3.0.10

# File lib/mongoid/relations/builders/nested_attributes/many.rb, line 162
def update_document(doc, attrs)
  attrs.delete_id
  if metadata.embedded?
    doc.assign_attributes(attrs)
  else
    doc.update_attributes(attrs)
  end
end