Module: ClosureTree::ActsAsTree

Defined in:
lib/closure_tree/acts_as_tree.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.hash_tree(options = {}) ⇒ Object



86
87
88
# File 'lib/closure_tree/acts_as_tree.rb', line 86

def self.hash_tree(options = {})
  roots.inject(ActiveSupport::OrderedHash.new) { |h, ea| h.merge(ea.hash_tree(options)) }
end

.leavesObject



90
91
92
93
# File 'lib/closure_tree/acts_as_tree.rb', line 90

def self.leaves
  s = joins(leaves_join_sql)
  order_option ? s.order(order_option) : s
end

.leaves_join_sqlObject



95
96
97
98
99
100
101
102
103
104
# File 'lib/closure_tree/acts_as_tree.rb', line 95

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

.rootsObject



82
83
84
# File 'lib/closure_tree/acts_as_tree.rb', line 82

def self.roots
  where(parent_column_name => nil)
end

Instance Method Details

#acts_as_tree(options = {}) ⇒ Object

Raises:

  • (IllegalArgumentException)


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, # or :destroy or :delete_all -- see the README
    :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

  # Auto-inject the hierarchy table
  # See https://github.com/patshaughnessy/class_factory/blob/master/lib/class_factory/class_factory.rb
  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
  # TODO: FIXME: this collection currently ignores sort_order
  # (because the quoted_table_named would need to be joined in to get to the order column)

  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