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/rational_numbering.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, Ordering, RationalNumbering, 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 174

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

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



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

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



279
280
281
# File 'lib/mongoid/tree.rb', line 279

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



287
288
289
# File 'lib/mongoid/tree.rb', line 287

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 198

#delete_descendantsvoid

This method returns an undefined value.

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



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

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



254
255
256
# File 'lib/mongoid/tree.rb', line 254

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



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

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



305
306
307
# File 'lib/mongoid/tree.rb', line 305

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



313
314
315
# File 'lib/mongoid/tree.rb', line 313

def descendants_and_self
  [self] + descendants
end

#destroy_childrenvoid

This method returns an undefined value.

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



411
412
413
# File 'lib/mongoid/tree.rb', line 411

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



242
243
244
# File 'lib/mongoid/tree.rb', line 242

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



357
358
359
# File 'lib/mongoid/tree.rb', line 357

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

#move_children_to_parentvoid

This method returns an undefined value.

Moves all children to this document’s parent



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

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

#nullify_childrenvoid

This method returns an undefined value.

Nullifies all children’s parent_id



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

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 206

#parent=(document) ⇒ Object

Note:

Generated by Mongoid

Sets this documents parent document.

Parameters:



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

#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 222

#rearrange_children!void

This method returns an undefined value.

Forces rearranging of all children after next save



365
366
367
# File 'lib/mongoid/tree.rb', line 365

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



373
374
375
# File 'lib/mongoid/tree.rb', line 373

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



267
268
269
270
271
272
273
# File 'lib/mongoid/tree.rb', line 267

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



234
235
236
# File 'lib/mongoid/tree.rb', line 234

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



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

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



331
332
333
# File 'lib/mongoid/tree.rb', line 331

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



339
340
341
# File 'lib/mongoid/tree.rb', line 339

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