Module: Mongoid::Tree

Extended by:
ActiveSupport::Concern
Defined in:
lib/mongoid/tree.rb,
lib/mongoid/tree/ordering.rb,
lib/mongoid/tree/traversal.rb,
lib/mongoid/tree/counter_caching.rb

Overview

Mongoid::Tree

This module extends any Mongoid document with tree functionality.

Usage

Simply include the module in any Mongoid document:

class Node
  include Mongoid::Document
  include Mongoid::Tree
end

Using the tree structure

Each document references many children. You can access them using the #children method.

node = Node.create
node.children.create
node.children.count # => 1

Every document references one parent (unless it’s a root document).

node = Node.create
node.parent # => nil
node.children.create
node.children.first.parent # => node

Destroying

Mongoid::Tree does not handle destroying of nodes by default. However it provides several strategies that help you to deal with children of deleted documents. You can simply add them as before_destroy callbacks.

Available strategies are:

  • :nullify_children – Sets the children’s parent_id to null

  • :move_children_to_parent – Moves the children to the current document’s parent

  • :destroy_children – Destroys all children by calling their #destroy method (invokes callbacks)

  • :delete_descendants – Deletes all descendants using a database query (doesn’t invoke callbacks)

Example:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  before_destroy :nullify_children
end

Callbacks

Mongoid::Tree offers callbacks for its rearranging process. This enables you to rebuild certain fields when the document was moved in the tree. Rearranging happens before the document is validated. This gives you a chance to validate your additional changes done in your callbacks. See ActiveModel::Callbacks and ActiveSupport::Callbacks for further details on callbacks.

Example:

class Page
  include Mongoid::Document
  include Mongoid::Tree

  after_rearrange :rebuild_path

  field :slug
  field :path

  private

  def rebuild_path
    self.path = self.ancestors_and_self.collect(&:slug).join('/')
  end
end

Defined Under Namespace

Modules: ClassMethods, CounterCaching, Ordering, Traversal

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.after_rearrangeundefined

Note:

Generated by ActiveSupport

Sets a callback that is called after the document is rearranged

Examples:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  after_rearrange :do_something

private

  def do_something
    # ...
  end
end

Returns:

  • (undefined)


# File 'lib/mongoid/tree.rb', line 185

.before_rearrangeundefined

Note:

Generated by ActiveSupport

Sets a callback that is called before the document is rearranged

Examples:

class Node
  include Mongoid::Document
  include Mongoid::Tree

  before_rearrage :do_something

private

  def do_something
    # ...
  end
end

Returns:

  • (undefined)


# File 'lib/mongoid/tree.rb', line 161

Instance Method Details

#ancestor_of?(other) ⇒ Boolean

Is this document an ancestor of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is an ancestor of the other document



308
309
310
# File 'lib/mongoid/tree.rb', line 308

def ancestor_of?(other)
  other.parent_ids.include?(self.id)
end

#ancestorsMongoid::Criteria

Returns a chainable criteria for this document’s ancestors

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the documents ancestors



290
291
292
# File 'lib/mongoid/tree.rb', line 290

def ancestors
  base_class.where(:_id.in => parent_ids).order(:depth => :asc)
end

#ancestors_and_selfArray<Mongoid::Document>

Returns an array of this document’s ancestors and itself

Returns:

  • (Array<Mongoid::Document>)

    Array of the document’s ancestors and itself



298
299
300
# File 'lib/mongoid/tree.rb', line 298

def ancestors_and_self
  ancestors + [self]
end

#childrenMongoid::Criteria

Note:

Generated by Mongoid

Returns a list of the document’s children. It’s a references_many association.

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s children



# File 'lib/mongoid/tree.rb', line 209

#delete_descendantsundefined

Deletes all descendants using the database (doesn’t invoke callbacks)

Returns:

  • (undefined)


414
415
416
# File 'lib/mongoid/tree.rb', line 414

def delete_descendants
  base_class.delete_all(:conditions => { :parent_ids => self.id })
end

#depthFixnum

Returns the depth of this document (number of ancestors)

Examples:

Node.root.depth # => 0
Node.root.children.first.depth # => 1

Returns:

  • (Fixnum)

    Depth of this document



249
250
251
# File 'lib/mongoid/tree.rb', line 249

def depth
  super || parent_ids.count
end

#descendant_of?(other) ⇒ Boolean

Is this document a descendant of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is a descendant of the other document



334
335
336
# File 'lib/mongoid/tree.rb', line 334

def descendant_of?(other)
  self.parent_ids.include?(other.id)
end

#descendantsMongoid::Criteria

Returns a chainable criteria for this document’s descendants

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s descendants



316
317
318
# File 'lib/mongoid/tree.rb', line 316

def descendants
  base_class.where(:parent_ids => self.id)
end

#descendants_and_selfArray<Mongoid::Document>

Returns and array of this document and it’s descendants

Returns:

  • (Array<Mongoid::Document>)

    Array of the document itself and it’s descendants



324
325
326
# File 'lib/mongoid/tree.rb', line 324

def descendants_and_self
  [self] + descendants
end

#destroy_childrenundefined

Destroys all children by calling their #destroy method (does invoke callbacks)

Returns:

  • (undefined)


422
423
424
# File 'lib/mongoid/tree.rb', line 422

def destroy_children
  children.destroy_all
end

#leaf?Boolean

Is this document a leaf node (has no children)?

Returns:

  • (Boolean)

    Whether the document is a leaf node



265
266
267
# File 'lib/mongoid/tree.rb', line 265

def leaf?
  children.empty?
end

#leavesMongoid::Criteria

Returns all leaves of this document (be careful, currently involves two queries)

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s leaves



368
369
370
# File 'lib/mongoid/tree.rb', line 368

def leaves
  base_class.where(:_id.nin => base_class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id)
end

#move_children_to_parentundefined

Moves all children to this document’s parent

Returns:

  • (undefined)


403
404
405
406
407
408
# File 'lib/mongoid/tree.rb', line 403

def move_children_to_parent
  children.each do |c|
    c.parent = self.parent
    c.save
  end
end

#nullify_childrenundefined

Nullifies all children’s parent_id

Returns:

  • (undefined)


392
393
394
395
396
397
# File 'lib/mongoid/tree.rb', line 392

def nullify_children
  children.each do |c|
    c.parent = c.parent_id = nil
    c.save
  end
end

#parentMongoid::Document

Note:

Generated by Mongoid

Returns the document’s parent (unless it’s a root document). It’s a referenced_in association.

Returns:

  • (Mongoid::Document)

    The document’s parent document



# File 'lib/mongoid/tree.rb', line 217

#parent=(document) ⇒ Object

Note:

Generated by Mongoid

Sets this documents parent document.

Parameters:



# File 'lib/mongoid/tree.rb', line 225

#parent_idsArray<BSON::ObjectId>

Note:

Generated by Mongoid

Returns a list of the document’s parent_ids, starting with the root node.

Returns:

  • (Array<BSON::ObjectId>)

    The ids of the document’s ancestors



# File 'lib/mongoid/tree.rb', line 233

#rearrange_children!undefined

Forces rearranging of all children after next save

Returns:

  • (undefined)


376
377
378
# File 'lib/mongoid/tree.rb', line 376

def rearrange_children!
  @rearrange_children = true
end

#rearrange_children?Boolean

Will the children be rearranged after next save?

Returns:

  • (Boolean)

    Whether the children will be rearranged



384
385
386
# File 'lib/mongoid/tree.rb', line 384

def rearrange_children?
  !!@rearrange_children
end

#rootMongoid::Document

Returns this document’s root node. Returns ‘self` if the current document is a root node

Examples:

node = Node.find(...)
node.root

Returns:

  • (Mongoid::Document)

    The documents root node



278
279
280
281
282
283
284
# File 'lib/mongoid/tree.rb', line 278

def root
  if parent_ids.present?
    base_class.find(parent_ids.first)
  else
    self.root? ? self : self.parent.root
  end
end

#root?Boolean

Is this document a root node (has no parent)?

Returns:

  • (Boolean)

    Whether the document is a root node



257
258
259
# File 'lib/mongoid/tree.rb', line 257

def root?
  parent_id.nil?
end

#sibling_of?(other) ⇒ Boolean

Is this document a sibling of the other document?

Parameters:

Returns:

  • (Boolean)

    The document is a sibling of the other document



360
361
362
# File 'lib/mongoid/tree.rb', line 360

def sibling_of?(other)
  self.parent_id == other.parent_id
end

#siblingsMongoid::Criteria

Returns this document’s siblings

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s siblings



342
343
344
# File 'lib/mongoid/tree.rb', line 342

def siblings
  siblings_and_self.excludes(:id => self.id)
end

#siblings_and_selfMongoid::Criteria

Returns this document’s siblings and itself

Returns:

  • (Mongoid::Criteria)

    Mongoid criteria to retrieve the document’s siblings and itself



350
351
352
# File 'lib/mongoid/tree.rb', line 350

def siblings_and_self
  base_class.where(:parent_id => self.parent_id)
end