123456789_123456789_123456789_123456789_123456789_

Class: Mongoid::Association::Embedded::EmbedsMany::Proxy

Relationships & Source Files
Namespace Children
Modules:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
Instance Chain:
Inherits: Mongoid::Association::Many
Defined in: lib/mongoid/association/embedded/embeds_many/proxy.rb

Overview

Transparent proxy for embeds_many associations. An instance of this class is returned when calling the association getter method on the parent document. This class inherits from Mongoid::Association::Proxy and forwards most of its methods to the target of the association, i.e. the array of child documents.

Constant Summary

::Mongoid::Association::Proxy - Inherited

KEEPER_METHODS

Class Attribute Summary

ClassMethods - Extended

embedded?

Returns true if the association is an embedded one.

Class Method Summary

ClassMethods - Extended

eager_loader

Returns the eager loader for this association.

foreign_key_suffix

Returns the suffix of the foreign key field, either “_id” or “_ids”.

::Mongoid::Association::Proxy - Inherited

.apply_ordering

Apply ordering to the criteria if it was defined on the association.

.new

Sets the target and the association metadata properties.

Instance Attribute Summary

::Mongoid::Association::Embedded::Batchable - Included

#insertable?

Are we in a state to be able to batch insert?

#inserts_valid

Are the inserts currently valid?

#inserts_valid=

::Set the inserts valid flag.

#path

Get the atomic path.

#path=

::Set the atomic path.

::Mongoid::Association::Many - Inherited

#blank?

Is the association empty?

#nil?

This proxy can never be nil.

::Mongoid::Association::Proxy - Inherited

#_association,
#_base

Model instance for the base of the association.

#_target

Model instance for one to one associations, or array of model instances for one to many associations, for the target of the association.

::Mongoid::Threaded::Lifecycle - Included

#_assigning

Begin the assignment of attributes.

#_assigning?

Is the current thread in assigning mode?

#_binding

Execute a block in binding mode.

#_binding?

Is the current thread in binding mode?

#_building

Execute a block in building mode.

#_building?

Is the current thread in building mode?

#_creating?

Is the current thread in creating mode?

#_loading

Execute a block in loading mode.

#_loading?

Is the current thread in loading mode?

Instance Method Summary

::Mongoid::Association::Embedded::Batchable - Included

#batch_clear

Clear all of the docs out of the association in a single swipe.

#batch_insert

Insert new documents as a batch push ($push with $each).

#batch_remove

Batch remove the provided documents as a $pullAll or $pull.

#batch_replace

Batch replace the provided documents as a $set.

#add_atomic_sets

Add the atomic sets to the base document.

#clear_atomic_path_cache

Clear the cache for path and atomic_paths.

#execute_batch_push

Perform a batch persist of the provided documents with $push and $each.

#execute_batch_set

Perform a batch persist of the provided documents with a $set.

#normalize_docs

Normalize the documents, in case they were provided as an array of hashes.

#post_process_batch_insert

Post process the documents after batch insert.

#post_process_batch_remove

Post process the batch removal.

#pre_process_batch_insert

Pre processes the batch insert for the provided documents.

#pre_process_batch_remove

Pre process the batch removal.

#selector

Get the selector for executing atomic operations on the collection.

::Mongoid::Positional - Included

#positionally

Takes the provided selector and atomic operations and replaces the indexes of the embedded documents with the positional operator when needed.

#process_operations, #process_updates, #replace_index

::Mongoid::Association::Many - Inherited

#create

Creates a new document on the references many association.

#create!

Creates a new document on the references many association.

#find_or_create_by

Find the first document given the conditions, or creates a new document with the conditions that were supplied.

#find_or_create_by!

Find the first document given the conditions, or creates a new document with the conditions that were supplied.

#find_or_initialize_by

Find the first Document given the conditions, or instantiates a new document with the conditions that were supplied.

#respond_to?

Since method_missing is overridden we should override this as well.

#scoped

This is public access to the association’s criteria.

#serializable_hash

Gets the document as a serializable hash, used by ActiveModel’s JSON and XML serializers.

#unscoped

Get a criteria for the embedded documents without the default scoping applied.

#_session,
#find_or

Find the first object given the supplied attributes or create/initialize it.

::Mongoid::Association::Proxy - Inherited

#extend_proxies

Allow extension to be an array and extend each module.

#extend_proxy,
#klass

Get the class from the association, or return nil if no association present.

#reset_unloaded

Resets the criteria inside the association proxy.

#substitutable

The default substitutable object for an association proxy is the clone of the target.

::Mongoid::Association::Marshalable - Included

#marshal_dump

Provides the data needed to Marshal.dump an association proxy.

#marshal_load

Takes the provided data and sets it back on the proxy.

Constructor Details

.new(base, target, association) ⇒ Many

Instantiate a new embeds_many association.

Examples:

Create the new association.

Many.new(person, addresses, association)

Parameters:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 67

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

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missingCriteria | 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.

TODO: make sure we are consistingly using respond_to_missing

anywhere we define method_missing.

Parameters:

  • name (Symbol | String)

    The name of the method.

  • *args (Object...)

    The method args.

  • &block

    Optional block to pass.

Returns:

  • (Criteria | Object)

    A Criteria or return value from the target.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 490

ruby2_keywords def method_missing(name, *args, &block)
  return super if _target.respond_to?(name)

  klass.send(:with_scope, criteria) do
    criteria.public_send(name, *args, &block)
  end
end

Instance Attribute Details

#_unscoped (rw, private)

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 423

attr_accessor :_unscoped

#persistable?true | false (readonly, private)

Are we able to persist this association?

Examples:

Can we persist the association?

relation.persistable?

Returns:

  • (true | false)

    If the association is persistable.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 505

def persistable?
  _base.persisted? && !_binding?
end

Instance Method Details

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

Appends a document or array of documents to the association. 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:

  • *args (Document...)

    Any number of documents.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 89

def <<(*args)
  docs = args.flatten
  return unless docs.any?
  return concat(docs) if docs.size > 1

  docs.first.tap do |doc|
    append(doc)
    doc.save if persistable? && !_assigning?
  end

  self
end

#_remove(document)

This method is for internal use only.

Removes a single document from the collection *in memory only*. It will not persist the change.

Parameters:

  • document (Document)

    The document to delete.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 236

def _remove(document)
  _target.delete_one(document)
  _unscoped.delete_one(document)
  update_attributes_hash
  reindex
end

#append(document) (private)

Appends the document to the target array, updating the index on the document at the same time.

Examples:

Append to the document.

relation.append(document)

Parameters:

  • document (Document)

    The document to append to the target.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 436

def append(document)
  execute_callback :before_add, document
  _target.push(*scope([ document ])) unless object_already_related?(document)
  _unscoped.push(document)
  integrate(document)
  update_attributes_hash
  document._index = _unscoped.size - 1
  execute_callback :after_add, document
end

#as_attributesArray<Hash> (private)

Returns a list of attributes hashes for each document.

Returns:

  • (Array<Hash>)

    The list of attributes hashes

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 560

def as_attributes
  _unscoped.map { |doc| doc.send(:as_attributes) }
end

#as_documentArray<Hash>

Get this association as as its representation in the database.

Examples:

Convert the association to an attributes hash.

person.addresses.as_document

Returns:

  • (Array<Hash>)

    The association as stored in the db.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 110

def as_document
  as_attributes.collect { |attrs| BSON::Document.new(attrs) }
end

#bindingBinding (private)

Instantiate the binding associated with this association.

Examples:

Create the binding.

relation.binding([ address ])

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 452

def binding
  Binding.new(_base, _target, _association)
end

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

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

Examples:

Build a new document on the association.

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

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:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 138

def build(attributes = {}, type = nil)
  Factory.execute_build(type || _association.klass, attributes, execute_callbacks: false).tap do |doc|
    append(doc)
    doc.apply_post_processed_defaults
    yield doc if block_given?
    doc.run_pending_callbacks
    doc.run_callbacks(:build) { doc }
    _base._reset_memoized_descendants!
  end
end

#clearself

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

If the host document is not persisted but its _id matches a persisted document, calling #clear on an association will remove the association’s documents from the database even though the set of documents in the application (as loaded in the host) is different from what is in the database, and the host may not contain any persisted documents in the association either.

Examples:

Clear the association.

person.addresses.clear

Returns:

  • (self)

    The empty association.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 165

def clear
  batch_clear(_target.dup)
  update_attributes_hash
  self
end

#concat(docs) ⇒ Array<Document>

Appends an array of documents to the association. 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:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 123

def concat(docs)
  batch_insert(docs) unless docs.empty?
  self
end

#count(*args, &block) ⇒ Integer

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.

If args or block are present, #count will delegate to the #count method on target and will include both persisted and non-persisted documents.

Examples:

Get the count of persisted documents.

person.addresses.count

Get the count of all documents matching a block.

person.addresses.count { |a| a.country == "FR" }

Use #persisted? inside block to count persisted documents.

person.addresses.count { |a| a.persisted? && a.country == "FR" }

Parameters:

  • *args (Object...)

    Args to delegate to the target.

Returns:

  • (Integer)

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

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 193

def count(*args, &block)
  return _target.count(*args, &block) if args.any? || block

  _target.count(&:persisted?)
end

#criteriaCriteria (private)

Returns the Criteria object for the target class with its documents set to the list of target documents in the association.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 460

def criteria
  _association.criteria(_base, _target)
end

#delete(document) ⇒ Document | nil Also known as: #delete_one

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 association.

person.addresses.delete(address)

Parameters:

  • document (Document)

    The document to be deleted.

Returns:

  • (Document | nil)

    The deleted document or nil if nothing deleted.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 208

def delete(document)
  execute_callbacks_around(:remove, document) do
    _target.delete_one(document).tap do |doc|
      if doc && !_binding?
        _unscoped.delete_one(doc)
        if _assigning?
          _base.add_atomic_pull(doc)
        else
          doc.delete(suppress: true)
          unbind_one(doc)
        end
        update_attributes_hash
      end
      reindex
    end
  end
end

#delete_all(conditions = {}) ⇒ Integer

Delete all the documents in the association without running callbacks.

Examples:

Delete all documents from the association.

person.addresses.delete_all

Conditionally delete documents from the association.

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

Parameters:

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

    Conditions on which documents to delete.

Returns:

  • (Integer)

    The number of documents deleted.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 254

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

#delete_ifEmbedsMany::Proxy | Enumerator

Delete all the documents for which the provided block returns true.

Examples:

Delete the matching documents.

person.addresses.delete_if do |doc|
  doc.state == "GA"
end

Returns:

  • (EmbedsMany::Proxy | Enumerator)

    The proxy or an enumerator if no block was provided.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 267

def delete_if
  return super unless block_given?

  _target.dup.each { |doc| delete(doc) if yield doc }

  self
end

#delete_one(document)

Alias for #delete.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 228

alias delete_one delete

#destroy_all(conditions = {}) ⇒ Integer

Destroy all the documents in the association whilst running callbacks.

Examples:

Destroy all documents from the association.

person.addresses.destroy_all

Conditionally destroy documents from the association.

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

Parameters:

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

    Conditions on which documents to destroy.

Returns:

  • (Integer)

    The number of documents destroyed.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 286

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

#exists?(id_or_conditions = :none) ⇒ true | false

Determine if any documents in this association exist in the database.

Examples:

Are there persisted documents?

person.posts.exists?

Parameters:

  • id_or_conditions (:none | nil | false | Hash | Object) (defaults to: :none)

    When :none (the default), returns true if any persisted documents exist in the association. When nil or false, this will always return false. When a ::Hash is given, this queries the documents in the association for those that match the given conditions, and returns true if any match which have been persisted. Any other argument is interpreted as an id, and queries for the existence of persisted documents in the association with a matching _id.

Returns:

  • (true | false)

    True if persisted documents exist, false if not.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 306

def exists?(id_or_conditions = :none)
  case id_or_conditions
  when :none then _target.any?(&:persisted?)
  when nil, false then false
  when Hash then where(id_or_conditions).any?(&:persisted?)
  else where(_id: id_or_conditions).any?(&:persisted?)
  end
end

#find {|Object| ... } ⇒ Document | Array<Document> | nil

Finds a document in this association through several different methods.

This method delegates to Mongoid::Criteria#find. If this method is not given a block, it returns one or many documents for the provided _id values.

If this method is given a block, it returns the first document of those found by the current ::Mongoid::Criteria object for which the block returns a truthy value.

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 ])

Finds the first matching document using a block.

person.addresses.find { |addr| addr.state == 'CA' }

Parameters:

  • *args (Object...)

    Various arguments.

  • &block

    Optional block to pass.

Yields:

  • (Object)

    Yields each enumerable element to the block.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 340

def find(...)
  criteria.find(...)
end

#in_memory

Alias for Proxy#_target.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 350

alias in_memory _target

#integrate(document) (private)

Integrate the document into the association. will set its metadata and attempt to bind the inverse.

Examples:

Integrate the document.

relation.integrate(document)

Parameters:

  • document (Document)

    The document to integrate.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 471

def integrate(document)
  characterize_one(document)
  bind_one(document)
end

#new(attributes = {}, type = nil)

Alias for #build.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 149

alias new build

#object_already_related?(document) ⇒ Boolean (private)

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 425

def object_already_related?(document)
  _target.any? { |existing| existing._id && existing == document }
end

#pop(count = nil) ⇒ Document | Array<Document> | nil

Pop documents off the association. This can be a single document or multiples, and will automatically persist the changes.

Examples:

Pop a single document.

relation.pop

Pop multiple documents.

relation.pop(3)

Parameters:

  • count (Integer) (defaults to: nil)

    The number of documents to pop, or 1 if not provided.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 365

def pop(count = nil)
  return [] if count&.zero?

  docs = _target.last(count || 1).each { |doc| delete(doc) }
  (count.nil? || docs.empty?) ? docs.first : docs
end

#push(*args)

Alias for #<<.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 102

alias push <<

#reindex (private)

Reindex all the target elements. This is useful when performing operations on the proxied target directly and the indices need to match that on the database side.

Examples:

Reindex the association.

person.addresses.reindex
[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 515

def reindex
  _unscoped.each_with_index do |doc, index|
    doc._index = index
  end
end

#remove_all(conditions = {}, method = :delete) ⇒ Integer (private)

Remove all documents from the association, either with a delete or a destroy depending on what this was called through.

Examples:

Destroy documents from the association.

relation.remove_all({ :num => 1 }, true)

Parameters:

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

    Conditions to filter by.

  • method (true | false) (defaults to: :delete)

    :delete or :destroy.

Returns:

  • (Integer)

    The number of documents removed.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 549

def remove_all(conditions = {}, method = :delete)
  criteria = where(conditions || {})
  criteria.size.tap do
    batch_remove(criteria, method)
    update_attributes_hash
  end
end

#scope(docs) ⇒ Array<Document> (private)

Apply the association ordering and default scoping (defined on association’s target class) to the provided documents.

Examples:

Apply scoping.

person.addresses.scope(target)

Parameters:

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 530

def scope(docs)
  return docs unless _association.order || _association.klass.default_scoping?

  crit = _association.klass.order_by(_association.order)
  crit.embedded = true
  crit.documents = docs
  crit.entries
end

#shift(count = nil) ⇒ Document | Array<Document> | nil

Shift documents off the association. This can be a single document or multiples, and will automatically persist the changes.

Examples:

Shift a single document.

relation.shift

Shift multiple documents.

relation.shift(3)

Parameters:

  • count (Integer) (defaults to: nil)

    The number of documents to shift, or 1 if not provided.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 385

def shift(count = nil)
  return [] if count&.zero?

  docs = _target.first(count || 1).each { |doc| delete(doc) }
  (count.nil? || docs.empty?) ? docs.first : docs
end

#substitute(docs) ⇒ Many

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

Examples:

Substitute the association’s target.

person.addresses.substitute([ address ])

Parameters:

Returns:

  • (Many)

    The proxied association.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 401

def substitute(docs)
  batch_replace(docs)
  update_attributes_hash
  self
end

#unscopedCriteria

Return the association 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:

  • (Criteria)

    The unscoped association.

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 414

def unscoped
  criterion = klass.unscoped
  criterion.embedded = true
  criterion.documents = _unscoped.delete_if(&:marked_for_destruction?)
  criterion
end

#update_attributes_hash (private)

This method is for internal use only.

Update the _base’s attributes hash with the _target’s attributes

[ GitHub ]

  
# File 'lib/mongoid/association/embedded/embeds_many/proxy.rb', line 567

def update_attributes_hash
  if _target.empty?
    _base.attributes.delete(_association.store_as)
  else
    _base.attributes.merge!(_association.store_as => _target.map(&:attributes))
  end
end