1

我正在做一件非常基本的事情 - 按拓扑顺序显示类别树,ActiveRecord 发出额外的查询以枚举每个类别的子项。

class Category < ActiveRecord::Base
  attr_accessible :name, :parent_id

  belongs_to :parent, :class_name => 'Category'
  has_many :children, :class_name => 'Category', :foreign_key => 'parent_id'

  def self.in_order
    all = Category.includes(:parent, :children).all  # Three queries as it should be
    root = all.find{|c| c.parent_id == nil}
    queue = [root]
    result = []
    while queue.any?
      current = queue.shift
      result << current
      current.children.each do |child|  # SELECT * FROM categories WHERE parent_id = ?
        queue << child
      end
    end
    result
  end
end

UPD。据我了解,当一个类别被称为某个类别的子类别时,它与初始列表中的对象不同,因此它没有加载它的子类别。有没有办法实现所需的行为而无需创建额外的邻接列表?

UPD2:这是手动邻接列表解决方案。它只使用一个查询,但我真的很想使用更惯用的东西

  def self.in_order_manual
    cache = {}
    adj = {}
    root = nil
    all.each do |c| 
      cache[c.id] = c
      if c.parent_id != nil
        (adj[c.parent_id] ||= []) << c.id
      else
        root = c.id
      end
    end

    queue = [root]
    result = []
    while queue.any?
      current = queue.shift
      result << current
      (adj[current] || []).each{|child| queue << child}
    end
    result.map{|id| cache[id]}
  end
4

0 回答 0