Class: Mongoid::Relations::Embedded::Many

Inherits:
Many show all
Includes:
Atomic
Defined in:
lib/mongoid/relations/embedded/many.rb

Overview

This class handles the behaviour for a document that embeds many other documents within in it as an array.

Constant Summary

Constants included from Atomic

Atomic::MODIFIERS

Instance Attribute Summary

Attributes inherited from Proxy

#base, #loaded, #metadata, #target

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Many

#blank?, #exists?, #find_or_create_by, #find_or_initialize_by, #nil?, #respond_to?, #scoped, #serializable_hash

Methods inherited from Proxy

#init, #substitutable

Constructor Details

#initialize(base, target, metadata) ⇒ Many

Instantiate a new embeds_many relation.

Examples:

Create the new relation.

Many.new(person, addresses, )

Parameters:

  • base (Document)

    The document this relation hangs off of.

  • target (Array<Document>)

    The child documents of the relation.

  • metadata (Metadata)

    The relation’s metadata



268
269
270
271
272
273
274
275
276
277
# File 'lib/mongoid/relations/embedded/many.rb', line 268

def initialize(base, target, )
  init(base, target, ) do
    target.each_with_index do |doc, index|
      integrate(doc)
      doc._index = index
    end
    @_unscoped = target.dup
    @target = scope(target)
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args, &block) ⇒ Criteria, Object (private)

If the target array does not respond to the supplied method then try to find a named scope or criteria on the class and send the call there.

If the method exists on the array, use the default proxy behavior.

Parameters:

  • name (Symbol, String)

    The name of the method.

  • args (Array)

    The method args

  • block (Proc)

    Optional block to pass.

Returns:



442
443
444
445
446
447
# File 'lib/mongoid/relations/embedded/many.rb', line 442

def method_missing(name, *args, &block)
  return super if target.respond_to?(name)
  klass.send(:with_scope, criteria) do
    criteria.send(name, *args, &block)
  end
end

Class Method Details

.builder(base, meta, object) ⇒ Builder

Return the builder that is responsible for generating the documents that will be used by this relation.

Examples:

Get the builder.

Embedded::Many.builder(meta, object)

Parameters:

  • base (Document)

    The base document.

  • meta (Metadata)

    The metadata of the relation.

  • object (Document, Hash)

    A document or attributes to build with.

Returns:

  • (Builder)

    A newly instantiated builder object.

Since:

  • 2.0.0.rc.1



558
559
560
# File 'lib/mongoid/relations/embedded/many.rb', line 558

def builder(base, meta, object)
  Builders::Embedded::Many.new(base, meta, object)
end

.embedded?true

Returns true if the relation is an embedded one. In this case always true.

Examples:

Is the relation embedded?

Embedded::Many.embedded?

Returns:

  • (true)

    true.

Since:

  • 2.0.0.rc.1



571
572
573
# File 'lib/mongoid/relations/embedded/many.rb', line 571

def embedded?
  true
end

.macroSymbol

Returns the macro for this relation. Used mostly as a helper in reflection.

Examples:

Get the relation macro.

Mongoid::Relations::Embedded::Many.macro

Returns:

Since:

  • 2.0.0.rc.1



584
585
586
# File 'lib/mongoid/relations/embedded/many.rb', line 584

def macro
  :embeds_many
end

.nested_builder(metadata, attributes, options) ⇒ NestedBuilder

Return the nested builder that is responsible for generating the documents that will be used by this relation.

Examples:

Get the nested builder.

NestedAttributes::Many.builder(attributes, options)

Parameters:

  • metadata (Metadata)

    The relation metadata.

  • attributes (Hash)

    The attributes to build with.

  • options (Hash)

    The builder options.

Options Hash (options):

  • :allow_destroy (true, false)

    Can documents be deleted?

  • :limit (Integer)

    Max number of documents to create at once.

  • :reject_if (Proc, Symbol)

    If documents match this option then they are ignored.

  • :update_only (true, false)

    Only existing documents can be modified.

Returns:

Since:

  • 2.0.0.rc.1



610
611
612
# File 'lib/mongoid/relations/embedded/many.rb', line 610

def nested_builder(, attributes, options)
  Builders::NestedAttributes::Many.new(, attributes, options)
end

.path(document) ⇒ Mongoid::Atomic::Paths::Embedded::Many

Get the path calculator for the supplied document.

Examples:

Get the path calculator.

Proxy.path(document)

Parameters:

  • document (Document)

    The document to calculate on.

Returns:

Since:

  • 2.1.0



625
626
627
# File 'lib/mongoid/relations/embedded/many.rb', line 625

def path(document)
  Mongoid::Atomic::Paths::Embedded::Many.new(document)
end

.stores_foreign_key?false

Tells the caller if this relation is one that stores the foreign key on its own objects.

Examples:

Does this relation store a foreign key?

Embedded::Many.stores_foreign_key?

Returns:

  • (false)

    false.

Since:

  • 2.0.0.rc.1



638
639
640
# File 'lib/mongoid/relations/embedded/many.rb', line 638

def stores_foreign_key?
  false
end

.valid_optionsArray<Symbol>

Get the valid options allowed with this relation.

Examples:

Get the valid options.

Relation.valid_options

Returns:

Since:

  • 2.1.0



650
651
652
# File 'lib/mongoid/relations/embedded/many.rb', line 650

def valid_options
  [ :as, :cascade_callbacks, :cyclic, :order, :versioned ]
end

.validation_defaulttrue, false

Get the default validation setting for the relation. Determines if by default a validates associated will occur.

Examples:

Get the validation default.

Proxy.validation_default

Returns:

  • (true, false)

    The validation default.

Since:

  • 2.1.9



663
664
665
# File 'lib/mongoid/relations/embedded/many.rb', line 663

def validation_default
  true
end

Instance Method Details

#<<(*args) ⇒ Object Also known as: push

Appends a document or array of documents to the relation. Will set the parent and update the index in the process.

Examples:

Append a document.

person.addresses << address

Push a document.

person.addresses.push(address)

Parameters:



21
22
23
24
25
26
27
28
# File 'lib/mongoid/relations/embedded/many.rb', line 21

def <<(*args)
  docs = args.flatten
  return concat(docs) if docs.size > 1
  if doc = docs.first
    append(doc)
    doc.save if persistable? && !_assigning?
  end
end

#as_documentArray<Hash>

Get this relation as as its representation in the database.

Examples:

Convert the relation to an attributes hash.

person.addresses.as_document

Returns:

  • (Array<Hash>)

    The relation as stored in the db.

Since:

  • 2.0.0.rc.1



39
40
41
42
43
44
45
# File 'lib/mongoid/relations/embedded/many.rb', line 39

def as_document
  [].tap do |attributes|
    _unscoped.each do |doc|
      attributes.push(doc.as_document)
    end
  end
end

#build(attributes = {}, options = {}, type = nil) ⇒ Document #build(attributes = {}, type = nil) ⇒ Document Also known as: new

Builds a new document in the relation and appends it to the target. Takes an optional type if you want to specify a subclass.

Examples:

Build a new document on the relation.

person.people.build(:name => "Bozo")

Overloads:

  • #build(attributes = {}, options = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

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

      The scoped assignment options.

    • type (Class) (defaults to: nil)

      Optional class to build the document with.

  • #build(attributes = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

    • type (Class) (defaults to: nil)

      Optional class to build the document with.

Returns:



89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/mongoid/relations/embedded/many.rb', line 89

def build(attributes = {}, options = {}, type = nil)
  if options.is_a? Class
    options, type = {}, options
  end

  Factory.build(type || .klass, attributes, options).tap do |doc|
    doc.identify
    append(doc)
    doc.apply_proc_defaults
    yield(doc) if block_given?
    doc.run_callbacks(:build) { doc }
  end
end

#clearMany

Clear the relation. Will delete the documents from the db if they are already persisted.

Examples:

Clear the relation.

person.addresses.clear

Returns:

  • (Many)

    The empty relation.



111
112
113
114
115
116
117
118
# File 'lib/mongoid/relations/embedded/many.rb', line 111

def clear
  tap do |proxy|
    atomically(:$unset) do
      proxy.delete_all
      _unscoped.clear
    end
  end
end

#concat(documents) ⇒ Array<Document>

Note:

When performing batch inserts the after callbacks will get executed before the documents have actually been persisted to the database due to an issue with Active Support’s callback system - we cannot explicitly fire the after callbacks by themselves.

Appends an array of documents to the relation. Performs a batch insert of the documents instead of persisting one at a time.

Examples:

Concat with other documents.

person.addresses.concat([ address_one, address_two ])

Parameters:

Returns:

Since:

  • 2.4.0



63
64
65
66
67
68
69
70
71
# File 'lib/mongoid/relations/embedded/many.rb', line 63

def concat(documents)
  atomically(:$pushAll) do
    documents.each do |doc|
      next unless doc
      append(doc)
      doc.save if persistable?
    end
  end
end

#countInteger

Returns a count of the number of documents in the association that have actually been persisted to the database.

Use #size if you want the total number of documents.

Examples:

Get the count of persisted documents.

person.addresses.count

Returns:

  • (Integer)

    The total number of persisted embedded docs, as flagged by the #persisted? method.



130
131
132
# File 'lib/mongoid/relations/embedded/many.rb', line 130

def count
  target.select { |doc| doc.persisted? }.size
end

#create(attributes = {}, options = {}, type = nil) ⇒ Document #create(attributes = {}, type = nil) ⇒ Document

Create a new document in the relation. This is essentially the same as doing a #build then #save on the new document.

Examples:

Create a new document in the relation.

person.movies.create(:name => "Bozo")

Overloads:

  • #create(attributes = {}, options = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

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

      The scoped assignment options.

    • type (Class) (defaults to: nil)

      Optional class to create the document with.

  • #create(attributes = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

    • type (Class) (defaults to: nil)

      Optional class to create the document with.

Returns:

  • (Document)

    The newly created document.



150
151
152
# File 'lib/mongoid/relations/embedded/many.rb', line 150

def create(attributes = {}, options = {}, type = nil, &block)
  build(attributes, options, type, &block).tap { |doc| doc.save }
end

#create!(attributes = {}, options = {}, type = nil) ⇒ Document #create!(attributes = {}, type = nil) ⇒ Document

Create a new document in the relation. This is essentially the same as doing a #build then #save on the new document. If validation failed on the document an error will get raised.

Examples:

Create the document.

person.addresses.create!(:street => "Unter der Linden")</tt>

Overloads:

  • #create!(attributes = {}, options = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

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

      The scoped assignment options.

    • type (Class) (defaults to: nil)

      Optional class to create the document with.

  • #create!(attributes = {}, type = nil) ⇒ Document

    Parameters:

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

      The attributes to build the document with.

    • type (Class) (defaults to: nil)

      Optional class to create the document with.

Returns:

  • (Document)

    The newly created document.

Raises:



173
174
175
# File 'lib/mongoid/relations/embedded/many.rb', line 173

def create!(attributes = {}, options = {}, type = nil, &block)
  build(attributes, options, type, &block).tap { |doc| doc.save! }
end

#delete(document) ⇒ Document?

Delete the supplied document from the target. This method is proxied in order to reindex the array after the operation occurs.

Examples:

Delete the document from the relation.

person.addresses.delete(address)

Parameters:

  • document (Document)

    The document to be deleted.

Returns:

  • (Document, nil)

    The deleted document or nil if nothing deleted.

Since:

  • 2.0.0.rc.1



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/mongoid/relations/embedded/many.rb', line 188

def delete(document)
  target.delete_one(document).tap do |doc|
    _unscoped.delete_one(doc)
    if doc && !_binding?
      if _assigning?
        if doc.paranoid?
          doc.destroy(:suppress => true)
        else
          base.add_atomic_pull(doc)
        end
      else
        doc.delete(:suppress => true)
        unbind_one(doc)
      end
    end
    reindex
  end
end

#delete_all(conditions = {}) ⇒ Integer

Delete all the documents in the association without running callbacks.

Examples:

Delete all documents from the relation.

person.addresses.delete_all

Conditionally delete documents from the relation.

person.addresses.delete_all(:conditions => { :street => "Bond" })

Parameters:

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

    Conditions on which documents to delete.

Returns:

  • (Integer)

    The number of documents deleted.



218
219
220
# File 'lib/mongoid/relations/embedded/many.rb', line 218

def delete_all(conditions = {})
  atomically(:$pull) { remove_all(conditions, :delete) }
end

#destroy_all(conditions = {}) ⇒ Integer

Destroy all the documents in the association whilst running callbacks.

Examples:

Destroy all documents from the relation.

person.addresses.destroy_all

Conditionally destroy documents from the relation.

person.addresses.destroy_all(:conditions => { :street => "Bond" })

Parameters:

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

    Conditions on which documents to destroy.

Returns:

  • (Integer)

    The number of documents destroyed.



233
234
235
# File 'lib/mongoid/relations/embedded/many.rb', line 233

def destroy_all(conditions = {})
  atomically(:$pull) { remove_all(conditions, :destroy) }
end

#find(*args) ⇒ Array<Document>, Document

Finds a document in this association through several different methods.

Examples:

Find a document by its id.

person.addresses.find(BSON::ObjectId.new)

Find documents for multiple ids.

person.addresses.find([ BSON::ObjectId.new, BSON::ObjectId.new ])

Find documents based on conditions.

person.addresses.find(:all, :conditions => { :number => 10 })
person.addresses.find(:first, :conditions => { :number => 10 })
person.addresses.find(:last, :conditions => { :number => 10 })

Parameters:

Returns:



254
255
256
# File 'lib/mongoid/relations/embedded/many.rb', line 254

def find(*args)
  criteria.find(*args)
end

#in_memoryArray<Document>

Get all the documents in the relation that are loaded into memory.

Examples:

Get the in memory documents.

relation.in_memory

Returns:

Since:

  • 2.1.0



287
288
289
# File 'lib/mongoid/relations/embedded/many.rb', line 287

def in_memory
  target
end

#substitute(replacement) ⇒ Many

Substitutes the supplied target documents for the existing documents in the relation.

Examples:

Substitute the relation’s target.

person.addresses.substitute([ address ])

Parameters:

  • new_target (Array<Document>)

    The replacement array.

  • building (true, false)

    Are we in build mode?

Returns:

  • (Many)

    The proxied relation.

Since:

  • 2.0.0.rc.1



303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
# File 'lib/mongoid/relations/embedded/many.rb', line 303

def substitute(replacement)
  tap do |proxy|
    if replacement.blank?
      if _assigning? && !proxy.empty?
        base.atomic_unsets.push(_unscoped.first.atomic_path)
      end
      proxy.clear
    else
      atomically(:$set) do
        base.delayed_atomic_sets.clear unless _assigning?
        if replacement.first.is_a?(Hash)
          replacement = replacement.map do |doc|
            attributes = { :metadata => , :_parent => base }
            attributes.merge!(doc)
            Factory.build(klass, attributes)
          end
        end
        docs = replacement.compact
        proxy.target = docs
        self._unscoped = docs.dup
        proxy.target.each_with_index do |doc, index|
          integrate(doc)
          doc._index = index
          doc.save if base.persisted? && !_assigning?
        end
        if _assigning?
          name = _unscoped.first.atomic_path
          base.delayed_atomic_sets[name].try(:clear)
          base._children.each do |child|
            child.delayed_atomic_sets.clear
          end
          base.instance_variable_set(:@_children, nil)
          base.delayed_atomic_sets[name] = proxy.as_document
        end
      end
    end
  end
end

#unscopedCriteria

Return the relation with all previous scoping removed. This is the exact representation of the docs in the database.

Examples:

Get the unscoped documents.

person.addresses.unscoped

Returns:

Since:

  • 2.4.0



351
352
353
354
355
# File 'lib/mongoid/relations/embedded/many.rb', line 351

def unscoped
  klass.criteria(true, false).tap do |criterion|
    criterion.documents = _unscoped
  end
end