Module: Mongoid::Traversable

Extended by:
ActiveSupport::Concern
Included in:
Composable
Defined in:
lib/mongoid/traversable.rb

Overview

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

Defined Under Namespace

Modules: ClassMethods, DiscriminatorAssignment, DiscriminatorRetrieval

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.__redefine(owner, name, value) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

[View source]

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 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 Method Details

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

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Get all child Documents to this Document

Returns:

  • (Array<Document>)

    All child documents in the hierarchy.

[View source]

238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/mongoid/traversable.rb', line 238

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 part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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.

[View source]

261
262
263
264
265
266
267
268
269
270
271
272
# File 'lib/mongoid/traversable.rb', line 261

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

#_parentMongoid::Document | nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Retrieves the parent document of this document.

Returns:

[View source]

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

def _parent
  @__parent || nil
end

#_parent=(document) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Sets the parent document of this document.

Parameters:

[View source]

121
122
123
# File 'lib/mongoid/traversable.rb', line 121

def _parent=(document)
  @__parent = document
end

#_reset_memoized_descendants!nil

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

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

Returns:

  • (nil)

    nil.

[View source]

388
389
390
391
392
# File 'lib/mongoid/traversable.rb', line 388

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

#_rootDocument

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.

[View source]

401
402
403
404
405
# File 'lib/mongoid/traversable.rb', line 401

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

#_root?true | false

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.

[View source]

413
414
415
# File 'lib/mongoid/traversable.rb', line 413

def _root?
  _parent ? false : true
end

#collect_childrenArray<Document>

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Collect all the children of this document.

Returns:

[View source]

279
280
281
282
283
284
285
286
287
288
# File 'lib/mongoid/traversable.rb', line 279

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 part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Collect all the descendants of this document.

Returns:

  • (Array<Document>)

    The descendants.

[View source]

295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/mongoid/traversable.rb', line 295

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:

  • (Array<Document>)

    The flagged descendants.

[View source]

321
322
323
324
325
# File 'lib/mongoid/traversable.rb', line 321

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

#hereditary?true | false

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.

[View source]

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

def hereditary?
  self.class.hereditary?
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:

[View source]

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

def parentize(document)
  self._parent = document
end

#remove_child(child) ⇒ Object

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.

[View source]

359
360
361
362
363
364
365
366
367
368
# File 'lib/mongoid/traversable.rb', line 359

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:

  • (Array<Document>)

    The descendants.

[View source]

374
375
376
377
378
379
380
# File 'lib/mongoid/traversable.rb', line 374

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