123456789_123456789_123456789_123456789_123456789_

Module: Mongoid::Traversable

Relationships & Source Files
Namespace Children
Modules:
Extension / Inclusion / Inheritance Descendants
Included In:
Super Chains via Extension / Inclusion / Inheritance
Class Chain:
self, ActiveSupport::Concern
Defined in: lib/mongoid/traversable.rb

Overview

Mixin module included in Document to provide behavior around traversing the document graph.

Class Method Summary

Instance Attribute Summary

Instance Method Summary

DSL Calls

included

[ GitHub ]


180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/mongoid/traversable.rb', line 180

included do
  class_attribute :discriminator_key, instance_accessor: false
  class << self
    # The class attribute declaration above creates a default getter which we override with our custom method.
    remove_method :discriminator_key
    delegate :discriminator_key, to: ::Mongoid
    prepend DiscriminatorAssignment
    include DiscriminatorRetrieval

    # @api private
    #
    # @return [ Hash<String, Class> ] The current mapping of discriminator_values to classes
    attr_accessor :discriminator_mapping
  end

  # Add a discriminator mapping to the parent class. This mapping is used when
  # receiving a document to identify its class.
  #
  # @param [ String ] value The discriminator_value that was just set
  # @param [ Class ] The class the discriminator_value was set on
  #
  # @api private
  def self.add_discriminator_mapping(value, klass = self)
    self.discriminator_mapping ||= {}
    self.discriminator_mapping[value] = klass
    superclass.add_discriminator_mapping(value, klass) if hereditary?
  end

  # Get the discriminator mapping from the parent class. This method returns nil if there
  # is no mapping for the given value.
  #
  # @param [ String ] value The discriminator_value to retrieve
  #
  # @return [ Class | nil ] klass The class corresponding to the given discriminator_value. If
  #                               the value is not in the mapping, this method returns nil.
  #
  # @api private
  def self.get_discriminator_mapping(value)
    self.discriminator_mapping[value] if self.discriminator_mapping
  end
end

Class Method Details

.__redefine(owner, name, value)

This method is for internal use only.
[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 17

def __redefine(owner, name, value)
  if owner.singleton_class?
    owner.redefine_method(name) { value }
    owner.send(:public, name)
  end
  owner.redefine_singleton_method(name) { value }
  owner.singleton_class.send(:public, name)
  owner.redefine_singleton_method("#{name}=") do |new_value|
    if owner.equal?(self)
      value = new_value
    else
      ::Mongoid::Traversable.redefine(self, name, new_value)
    end
  end
  owner.singleton_class.send(:public, "#{name}=")
end

Instance Attribute Details

#_parentMongoid::Document | nil (rw)

This method is for internal use only.

Retrieves the parent document of this document.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 97

def _parent
  @__parent || nil
end

#_parent=(document) (rw)

This method is for internal use only.

Sets the parent document of this document.

Parameters:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 109

def _parent=(document)
  @__parent = document
end

#_rootDocument (readonly)

Return the root document in the object graph. If the current document is the root object in the graph it will return self.

Examples:

Get the root document in the hierarchy.

document._root

Returns:

  • (Document)

    The root document in the hierarchy.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 390

def _root
  object = self
  object = object._parent while object._parent
  object
end

#_root?true | false (readonly)

Is this document the root document of the hierarchy?

Examples:

Is the document the root?

document._root?

Returns:

  • (true | false)

    If the document is the root.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 402

def _root?
  _parent ? false : true
end

#hereditary?true | false (readonly)

Determines if the document is a subclass of another document.

Examples:

Check if the document is a subclass

Square.new.hereditary?

Returns:

  • (true | false)

    True if hereditary, false if not.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 322

def hereditary?
  self.class.hereditary?
end

Instance Method Details

#_children(reset: false) ⇒ Array<Document>

This method is for internal use only.

Get all child Documents to this Document

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 227

def _children(reset: false)
  # See discussion above for the `_parent` method, as to why the variable
  # here needs to have two underscores.
  #
  # rubocop:disable Naming/MemoizedInstanceVariableName
  if reset
    @__children = nil
  else
    @__children ||= collect_children
  end
  # rubocop:enable Naming/MemoizedInstanceVariableName
end

#_descendants(reset: false) ⇒ Array<Document>

This method is for internal use only.

Get all descendant Documents of this Document recursively. This is used when calling update persistence operations from the root document, where changes in the entire tree need to be determined. Note that persistence from the embedded documents will always be preferred, since they are optimized calls… This operation can get expensive in domains with large hierarchies.

Returns:

  • (Array<Document>)

    All descendant documents in the hierarchy.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 250

def _descendants(reset: false)
  # See discussion above for the `_parent` method, as to why the variable
  # here needs to have two underscores.
  #
  # rubocop:disable Naming/MemoizedInstanceVariableName
  if reset
    @__descendants = nil
  else
    @__descendants ||= collect_descendants
  end
  # rubocop:enable Naming/MemoizedInstanceVariableName
end

#_reset_memoized_descendants!nil

This method is for internal use only.

Resets the memoized descendants on the object. Called internally when an embedded array changes size.

Returns:

  • (nil)

    nil.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 377

def _reset_memoized_descendants!
  _parent&._reset_memoized_descendants!
  _children reset: true
  _descendants reset: true
end

#collect_childrenArray<Document>

This method is for internal use only.

Collect all the children of this document.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 268

def collect_children
  [].tap do |children|
    embedded_relations.each_pair do |name, _association|
      without_autobuild do
        child = send(name)
        children.concat(Array.wrap(child)) if child
      end
    end
  end
end

#collect_descendantsArray<Document>

This method is for internal use only.

Collect all the descendants of this document.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 284

def collect_descendants
  children = []
  to_expand = _children
  expanded = {}

  until to_expand.empty?
    expanding = to_expand
    to_expand = []
    expanding.each do |child|
      next if expanded[child]

      # Don't mark expanded if _id is nil, since documents are compared by
      # their _ids, multiple embedded documents with nil ids will compare
      # equally, and some documents will not be expanded.
      expanded[child] = true if child._id
      children << child
      to_expand += child._children
    end
  end

  children
end

#flag_descendants_persistedArray<Document>

Marks all descendants as being persisted.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 310

def flag_descendants_persisted
  _descendants.each do |child|
    child.new_record = false
  end
end

#parentize(document) ⇒ Document

Sets up a child/parent association. This is used for newly created objects so they can be properly added to the graph.

Examples:

::Set the parent document.

document.parentize(parent)

Parameters:

  • document (Document)

    The parent document.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 335

def parentize(document)
  self._parent = document
end

#remove_child(child)

Remove a child document from this parent. If an embeds one then set to nil, otherwise remove from the embeds many.

This is called from the RemoveEmbedded persistence command.

Examples:

Remove the child.

document.remove_child(child)

Parameters:

  • child (Document)

    The child (embedded) document to remove.

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 348

def remove_child(child)
  name = child.association_name
  if child.embedded_one?
    attributes.delete(child._association.store_as)
    remove_ivar(name)
  else
    relation = send(name)
    relation._remove(child)
  end
end

#reset_persisted_descendantsArray<Document>

After descendants are persisted we can call this to move all their changes and flag them as persisted in one call.

Returns:

[ GitHub ]

  
# File 'lib/mongoid/traversable.rb', line 363

def reset_persisted_descendants
  _descendants.each do |child|
    child.move_changes
    child.new_record = false
  end
  _reset_memoized_descendants!
end