Method: Edge::Forest::ClassMethods#find_forest

Defined in:
lib/edge/forest.rb

#find_forestObject

Finds entire forest and preloads all associations. It can be used at the end of an ActiveRecord finder chain.

Example:

# loads all locations
Location.find_forest

# loads all nodes with matching names and all there descendants
Category.where(:name => %w{clothing books electronics}).find_forest


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
# File 'lib/edge/forest.rb', line 54

def find_forest
  new_scope = unscoped.joins("INNER JOIN all_nodes USING(#{connection.quote_column_name primary_key})")
  new_scope = new_scope.order(forest_order) if forest_order

  sql = <<-SQL
    #{cte_sql}
    #{new_scope.to_sql}
  SQL
  records = find_by_sql sql

  records_by_id = records.each_with_object({}) { |r, h| h[r.id] = r }

  # Set all children associations to an empty array
  records.each do |r|
    children_association = r.association(:children)
    children_association.target = []
  end

  top_level_records = []

  records.each do |r|
    parent = records_by_id[r[forest_foreign_key]]
    if parent
      r.association(:parent).target = parent
      parent.association(:children).target.push(r)
    else
      top_level_records.push(r)
    end
  end

  top_level_records
end