To check out this repository please hg clone the following URL, or open the URL using EasyMercurial or your preferred Mercurial client.
root / vendor / plugins / acts_as_tree / lib / active_record / acts / tree.rb @ 442:753f1380d6bc
History | View | Annotate | Download (4.45 KB)
| 1 |
module ActiveRecord |
|---|---|
| 2 |
module Acts |
| 3 |
module Tree |
| 4 |
def self.included(base) |
| 5 |
base.extend(ClassMethods)
|
| 6 |
end
|
| 7 |
|
| 8 |
# Specify this +acts_as+ extension if you want to model a tree structure by providing a parent association and a children
|
| 9 |
# association. This requires that you have a foreign key column, which by default is called +parent_id+.
|
| 10 |
#
|
| 11 |
# class Category < ActiveRecord::Base
|
| 12 |
# acts_as_tree :order => "name"
|
| 13 |
# end
|
| 14 |
#
|
| 15 |
# Example:
|
| 16 |
# root
|
| 17 |
# \_ child1
|
| 18 |
# \_ subchild1
|
| 19 |
# \_ subchild2
|
| 20 |
#
|
| 21 |
# root = Category.create("name" => "root")
|
| 22 |
# child1 = root.children.create("name" => "child1")
|
| 23 |
# subchild1 = child1.children.create("name" => "subchild1")
|
| 24 |
#
|
| 25 |
# root.parent # => nil
|
| 26 |
# child1.parent # => root
|
| 27 |
# root.children # => [child1]
|
| 28 |
# root.children.first.children.first # => subchild1
|
| 29 |
#
|
| 30 |
# In addition to the parent and children associations, the following instance methods are added to the class
|
| 31 |
# after calling <tt>acts_as_tree</tt>:
|
| 32 |
# * <tt>siblings</tt> - Returns all the children of the parent, excluding the current node (<tt>[subchild2]</tt> when called on <tt>subchild1</tt>)
|
| 33 |
# * <tt>self_and_siblings</tt> - Returns all the children of the parent, including the current node (<tt>[subchild1, subchild2]</tt> when called on <tt>subchild1</tt>)
|
| 34 |
# * <tt>ancestors</tt> - Returns all the ancestors of the current node (<tt>[child1, root]</tt> when called on <tt>subchild2</tt>)
|
| 35 |
# * <tt>root</tt> - Returns the root of the current node (<tt>root</tt> when called on <tt>subchild2</tt>)
|
| 36 |
module ClassMethods |
| 37 |
# Configuration options are:
|
| 38 |
#
|
| 39 |
# * <tt>foreign_key</tt> - specifies the column name to use for tracking of the tree (default: +parent_id+)
|
| 40 |
# * <tt>order</tt> - makes it possible to sort the children according to this SQL snippet.
|
| 41 |
# * <tt>counter_cache</tt> - keeps a count in a +children_count+ column if set to +true+ (default: +false+).
|
| 42 |
def acts_as_tree(options = {}) |
| 43 |
configuration = { :foreign_key => "parent_id", :dependent => :destroy, :order => nil, :counter_cache => nil }
|
| 44 |
configuration.update(options) if options.is_a?(Hash) |
| 45 |
|
| 46 |
belongs_to :parent, :class_name => name, :foreign_key => configuration[:foreign_key], :counter_cache => configuration[:counter_cache] |
| 47 |
has_many :children, :class_name => name, :foreign_key => configuration[:foreign_key], :order => configuration[:order], :dependent => configuration[:dependent] |
| 48 |
|
| 49 |
class_eval <<-EOV |
| 50 |
include ActiveRecord::Acts::Tree::InstanceMethods
|
| 51 |
|
| 52 |
def self.roots
|
| 53 |
find(:all, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
| 54 |
end
|
| 55 |
|
| 56 |
def self.root
|
| 57 |
find(:first, :conditions => "#{configuration[:foreign_key]} IS NULL", :order => #{configuration[:order].nil? ? "nil" : %Q{"#{configuration[:order]}"}})
|
| 58 |
end
|
| 59 |
EOV
|
| 60 |
end
|
| 61 |
end
|
| 62 |
|
| 63 |
module InstanceMethods |
| 64 |
# Returns list of ancestors, starting from parent until root.
|
| 65 |
#
|
| 66 |
# subchild1.ancestors # => [child1, root]
|
| 67 |
def ancestors |
| 68 |
node, nodes = self, []
|
| 69 |
nodes << node = node.parent while node.parent
|
| 70 |
nodes |
| 71 |
end
|
| 72 |
|
| 73 |
# Returns list of descendants.
|
| 74 |
#
|
| 75 |
# root.descendants # => [child1, subchild1, subchild2]
|
| 76 |
def descendants |
| 77 |
children + children.collect(&:children).flatten
|
| 78 |
end
|
| 79 |
|
| 80 |
# Returns list of descendants and a reference to the current node.
|
| 81 |
#
|
| 82 |
# root.self_and_descendants # => [root, child1, subchild1, subchild2]
|
| 83 |
def self_and_descendants |
| 84 |
[self] + descendants
|
| 85 |
end
|
| 86 |
|
| 87 |
# Returns the root node of the tree.
|
| 88 |
def root |
| 89 |
node = self
|
| 90 |
node = node.parent while node.parent
|
| 91 |
node |
| 92 |
end
|
| 93 |
|
| 94 |
# Returns all siblings of the current node.
|
| 95 |
#
|
| 96 |
# subchild1.siblings # => [subchild2]
|
| 97 |
def siblings |
| 98 |
self_and_siblings - [self]
|
| 99 |
end
|
| 100 |
|
| 101 |
# Returns all siblings and a reference to the current node.
|
| 102 |
#
|
| 103 |
# subchild1.self_and_siblings # => [subchild1, subchild2]
|
| 104 |
def self_and_siblings |
| 105 |
parent ? parent.children : self.class.roots
|
| 106 |
end
|
| 107 |
end
|
| 108 |
end
|
| 109 |
end
|
| 110 |
end
|