Module: Mongoid::Tree
- Extended by:
- ActiveSupport::Concern
- Defined in:
- lib/mongoid/tree.rb,
lib/mongoid/tree/ordering.rb,
lib/mongoid/tree/traversal.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, Traversal
Instance Method Summary collapse
-
#ancestor_of?(other) ⇒ Boolean
Is this document an ancestor of the other document?.
-
#ancestors ⇒ Object
Returns a chainable criteria for this document’s ancestors.
-
#ancestors_and_self ⇒ Object
Returns an array of this document’s ancestors and itself.
-
#delete_descendants ⇒ Object
Deletes all descendants using the database (doesn’t invoke callbacks).
-
#depth ⇒ Object
Returns the depth of this document (number of ancestors).
-
#descendant_of?(other) ⇒ Boolean
Is this document a descendant of the other document?.
-
#descendants ⇒ Object
Returns a chainable criteria for this document’s descendants.
-
#descendants_and_self ⇒ Object
Returns and array of this document’s descendants and itself.
-
#destroy_children ⇒ Object
Destroys all children by calling their #destroy method (does invoke callbacks).
-
#leaf? ⇒ Boolean
Is this document a leaf node (has no children)?.
-
#leaves ⇒ Object
Returns all leaves of this document (be careful, currently involves two queries).
-
#move_children_to_parent ⇒ Object
Moves all children to this document’s parent.
-
#nullify_children ⇒ Object
Nullifies all children’s parent_id.
-
#rearrange_children! ⇒ Object
Forces rearranging of all children after next save.
-
#rearrange_children? ⇒ Boolean
Will the children be rearranged after next save?.
-
#root ⇒ Object
Returns this document’s root node.
-
#root? ⇒ Boolean
Is this document a root node (has no parent)?.
-
#sibling_of?(other) ⇒ Boolean
Is this document a sibling of the other document?.
-
#siblings ⇒ Object
Returns this document’s siblings.
-
#siblings_and_self ⇒ Object
Returns this document’s siblings and itself.
Instance Method Details
#ancestor_of?(other) ⇒ Boolean
Is this document an ancestor of the other document?
210 211 212 |
# File 'lib/mongoid/tree.rb', line 210 def ancestor_of?(other) other.parent_ids.include?(self.id) end |
#ancestors ⇒ Object
Returns a chainable criteria for this document’s ancestors
198 199 200 |
# File 'lib/mongoid/tree.rb', line 198 def ancestors base_class.where(:_id.in => parent_ids) end |
#ancestors_and_self ⇒ Object
Returns an array of this document’s ancestors and itself
204 205 206 |
# File 'lib/mongoid/tree.rb', line 204 def ancestors_and_self ancestors + [self] end |
#delete_descendants ⇒ Object
Deletes all descendants using the database (doesn’t invoke callbacks)
288 289 290 |
# File 'lib/mongoid/tree.rb', line 288 def delete_descendants base_class.delete_all(:conditions => { :parent_ids => self.id }) end |
#depth ⇒ Object
Returns the depth of this document (number of ancestors)
182 183 184 |
# File 'lib/mongoid/tree.rb', line 182 def depth parent_ids.count end |
#descendant_of?(other) ⇒ Boolean
Is this document a descendant of the other document?
228 229 230 |
# File 'lib/mongoid/tree.rb', line 228 def descendant_of?(other) self.parent_ids.include?(other.id) end |
#descendants ⇒ Object
Returns a chainable criteria for this document’s descendants
216 217 218 |
# File 'lib/mongoid/tree.rb', line 216 def descendants base_class.where(:parent_ids => self.id) end |
#descendants_and_self ⇒ Object
Returns and array of this document’s descendants and itself
222 223 224 |
# File 'lib/mongoid/tree.rb', line 222 def descendants_and_self [self] + descendants end |
#destroy_children ⇒ Object
Destroys all children by calling their #destroy method (does invoke callbacks)
294 295 296 |
# File 'lib/mongoid/tree.rb', line 294 def destroy_children children.destroy_all end |
#leaf? ⇒ Boolean
Is this document a leaf node (has no children)?
176 177 178 |
# File 'lib/mongoid/tree.rb', line 176 def leaf? children.empty? end |
#leaves ⇒ Object
Returns all leaves of this document (be careful, currently involves two queries)
252 253 254 |
# File 'lib/mongoid/tree.rb', line 252 def leaves base_class.where(:_id.nin => base_class.only(:parent_id).collect(&:parent_id)).and(:parent_ids => self.id) end |
#move_children_to_parent ⇒ Object
Moves all children to this document’s parent
279 280 281 282 283 284 |
# File 'lib/mongoid/tree.rb', line 279 def move_children_to_parent children.each do |c| c.parent_id = self.parent_id c.save end end |
#nullify_children ⇒ Object
Nullifies all children’s parent_id
270 271 272 273 274 275 |
# File 'lib/mongoid/tree.rb', line 270 def nullify_children children.each do |c| c.parent = c.parent_id = nil c.save end end |
#rearrange_children! ⇒ Object
Forces rearranging of all children after next save
258 259 260 |
# File 'lib/mongoid/tree.rb', line 258 def rearrange_children! @rearrange_children = true end |
#rearrange_children? ⇒ Boolean
Will the children be rearranged after next save?
264 265 266 |
# File 'lib/mongoid/tree.rb', line 264 def rearrange_children? !!@rearrange_children end |
#root ⇒ Object
Returns this document’s root node
188 189 190 191 192 193 194 |
# File 'lib/mongoid/tree.rb', line 188 def root if parent_ids.present? return base_class.find(parent_ids.first) else return self.root? ? self : self.parent.root end end |
#root? ⇒ Boolean
Is this document a root node (has no parent)?
170 171 172 |
# File 'lib/mongoid/tree.rb', line 170 def root? parent_id.nil? end |
#sibling_of?(other) ⇒ Boolean
Is this document a sibling of the other document?
246 247 248 |
# File 'lib/mongoid/tree.rb', line 246 def sibling_of?(other) self.parent_id == other.parent_id end |
#siblings ⇒ Object
Returns this document’s siblings
234 235 236 |
# File 'lib/mongoid/tree.rb', line 234 def siblings siblings_and_self.excludes(:id => self.id) end |
#siblings_and_self ⇒ Object
Returns this document’s siblings and itself
240 241 242 |
# File 'lib/mongoid/tree.rb', line 240 def siblings_and_self base_class.where(:parent_id => self.parent_id) end |