3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
|
# File 'lib/closure_tree/acts_as_tree.rb', line 3
def acts_as_tree(options = {})
class_attribute :closure_tree_options
self.closure_tree_options = {
:parent_column_name => 'parent_id',
:dependent => :nullify, :name_column => 'name'
}.merge(options)
raise IllegalArgumentException, "name_column can't be 'path'" if closure_tree_options[:name_column] == 'path'
include ClosureTree::Columns
extend ClosureTree::Columns
class_attribute :hierarchy_class
self.hierarchy_class = Object.const_set hierarchy_class_name, Class.new(ActiveRecord::Base)
self.hierarchy_class.class_eval <<-RUBY
belongs_to :ancestor, :class_name => "#{ct_class.to_s}"
belongs_to :descendant, :class_name => "#{ct_class.to_s}"
attr_accessible :ancestor, :descendant, :generations
def ==(comparison_object)
comparison_object.instance_of?(self.class) &&
self.attributes == comparison_object.attributes
end
alias :eql? :==
RUBY
unless order_option.nil?
include ClosureTree::DeterministicOrdering
include ClosureTree::DeterministicNumericOrdering if order_is_numeric
end
include ClosureTree::Model
validate :ct_validate
before_save :ct_before_save
after_save :ct_after_save
before_destroy :ct_before_destroy
belongs_to :parent,
:class_name => ct_class.to_s,
:foreign_key => parent_column_name
attr_accessible :parent
has_many :children, with_order_option(
:class_name => ct_class.to_s,
:foreign_key => parent_column_name,
:dependent => closure_tree_options[:dependent]
)
has_many :ancestor_hierarchies,
:class_name => hierarchy_class_name,
:foreign_key => "descendant_id",
:order => "#{quoted_hierarchy_table_name}.generations asc",
:dependent => :destroy
has_many :self_and_ancestors,
:through => :ancestor_hierarchies,
:source => :ancestor,
:order => "#{quoted_hierarchy_table_name}.generations asc"
has_many :descendant_hierarchies,
:class_name => hierarchy_class_name,
:foreign_key => "ancestor_id",
:order => "#{quoted_hierarchy_table_name}.generations asc",
:dependent => :destroy
has_many :self_and_descendants,
:through => :descendant_hierarchies,
:source => :descendant,
:order => append_order("#{quoted_hierarchy_table_name}.generations asc")
def self.roots
where(parent_column_name => nil)
end
def self.hash_tree(options = {})
roots.inject(ActiveSupport::OrderedHash.new) { |h, ea| h.merge(ea.hash_tree(options)) }
end
def self.leaves
s = joins(leaves_join_sql)
order_option ? s.order(order_option) : s
end
def self.leaves_join_sql
<<-SQL
INNER JOIN
(SELECT ancestor_id
FROM #{quoted_hierarchy_table_name}
GROUP BY 1
HAVING MAX(#{quoted_hierarchy_table_name}.generations) = 0) AS leaves
ON (#{quoted_table_name}.#{primary_key} = leaves.ancestor_id)
SQL
end
end
|