123456789_123456789_123456789_123456789_123456789_

Class: Mongoid::Association::Nested::Many

Relationships & Source Files
Super Chains via Extension / Inclusion / Inheritance
Instance Chain:
self, Buildable
Inherits: Object
Defined in: lib/mongoid/association/nested/many.rb

Overview

Builder class used to perform #accepts_nested_attributes_for attribute assignment on many-to-n associations.

Class Method Summary

Instance Attribute Summary

Buildable - Included

#allow_destroy?

Determines if destroys are allowed for this document.

#association, #attributes, #existing, #options,
#update_only?

Determines if only updates can occur.

Instance Method Summary

Buildable - Included

#convert_id

Convert an id to its appropriate type.

#reject?

Returns the reject if option defined with the macro.

#delete_id

Deletes the id key from the given hash.

#extract_id

Get the id attribute from the given hash, whether it’s prefixed with an underscore or is a symbol.

Constructor Details

.new(association, attributes, options = {}) ⇒ Many

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

Examples:

Initialize the builder.

Many.new(association, attributes, options)

Parameters:

  • association (Mongoid::Association::Relatable)

    The association metadata.

  • attributes (Hash)

    The attributes hash to attempt to set.

  • options (Hash) (defaults to: {})

    The options defined.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 50

def initialize(association, 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
  @association = association
  @options = options
  @class_name = options[:class_name] ? options[:class_name].constantize : association.klass
end

Instance Method Details

#build(parent, options = {}) ⇒ Array

Builds the association 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 association, a replacement of the association with a new document, or a removal of the association.

Examples:

Build the nested attrs.

many.build(person)

Parameters:

  • parent (Document)

    The parent document of the association.

  • options (Hash) (defaults to: {})

    The options.

Returns:

  • (Array)

    The attributes.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 27

def build(parent, options = {})
  @existing = parent.send(association.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

#destroy(parent, relation, doc) (private)

This method is for internal use only.

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

Examples:

Destroy the child.

builder.destroy(parent, relation, doc)

Parameters:

  • parent (Document)

    The parent document.

  • relation (Proxy)

    The association proxy.

  • doc (Document)

    The doc to destroy.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 123

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) (private)

This method is for internal use only.

Destroy the document.

Examples:

Destroy the document.

builder.destroy_document(relation, doc)

Parameters:

  • relation (Proxy)

    The association proxy.

  • doc (Document)

    The document to delete.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 141

def destroy_document(relation, doc)
  res = doc.destroy unless doc.embedded? || doc.destroyed?
  relation.delete(doc)
  res
end

#destroyable?(attributes) ⇒ true | false (private)

Can the existing association potentially be deleted?

Examples:

Is the document destroyable?

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

Parameters:

  • attributes (Hash)

    The attributes to pull the flag from.

Returns:

  • (true | false)

    If the association can potentially be deleted.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 73

def destroyable?(attributes)
  destroy = attributes.delete(:_destroy)
  Nested::DESTROY_FLAGS.include?(destroy) && allow_destroy?
end

#over_limit?(attributes) ⇒ true | false (private)

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

Examples:

Are we over the set limit?

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

Parameters:

  • attributes (Hash)

    The attributes being set.

Returns:

  • (true | false)

    If the attributes exceed the limit.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 87

def over_limit?(attributes)
  limit = options[:limit]
  limit ? attributes.size > limit : false
end

#process_attributes(parent, attrs) (private)

This method is for internal use only.

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

Examples:

Process the attributes

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

Parameters:

  • parent (Document)

    The parent document.

  • attrs (Hash)

    The single document attributes to process.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 102

def process_attributes(parent, attrs)
  return if reject?(parent, attrs)

  if (id = extract_id(attrs))
    update_nested_relation(parent, id, attrs)
  else
    existing.push(Factory.build(@class_name, attrs)) unless destroyable?(attrs)
  end
end

#update_document(doc, attrs) (private)

This method is for internal use only.

Update the document.

Examples:

Update the document.

builder.update_document(doc, {}, options)

Parameters:

  • doc (Document)

    The document to update.

  • attrs (Hash)

    The attributes.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 156

def update_document(doc, attrs)
  delete_id(attrs)
  if association.embedded?
    doc.assign_attributes(attrs)
  else
    doc.update_attributes(attrs)
  end
end

#update_nested_relation(parent, id, attrs) (private)

This method is for internal use only.

Update nested association.

Examples:

Update nested association.

builder.update_nested_relation(parent, id, attrs)

Parameters:

  • parent (Document)

    The parent document.

  • id (String | BSON::ObjectId)

    of the related document.

  • attrs (Hash)

    The single document attributes to process.

[ GitHub ]

  
# File 'lib/mongoid/association/nested/many.rb', line 175

def update_nested_relation(parent, id, attrs)
  first = existing.first
  converted = first ? convert_id(first.class, id) : id

  if existing.where(_id: converted).exists?
    # document exists in association
    doc = existing.find(converted)
    if destroyable?(attrs)
      destroy(parent, existing, doc)
    else
      update_document(doc, attrs)
    end
  else
    # push existing document to association
    doc = association.klass.unscoped.find(converted)
    update_document(doc, attrs)
    existing.push(doc) unless destroyable?(attrs)
  end
end