我在我的Rails项目中使用了
awesome_nested_set
插件.我有两个看起来像这样的模型(简化):
class Customer < ActiveRecord::Base has_many :categories end class Category < ActiveRecord::Base belongs_to :customer # Columns in the categories table: lft,rgt and parent_id acts_as_nested_set :scope => :customer_id validates_presence_of :name # Further validations... end
数据库中的树按预期构造. parent_id,lft和rgt的所有值都是正确的.树有多个根节点(当然在awesome_nested_set中允许).
现在,我想在一个正确排序的树中呈现给定客户的所有类别,例如结构:例如嵌套< ul>标签.这不会太难,但我需要它才能有效(SQL查询越少越好).
更新:计算出可以在没有进一步SQL查询的情况下计算树中任何给定节点的子节点数:number_of_children =(node.rgt – node.lft – 1)/ 2.这并不能解决问题,但可能会有所帮助.
解决方法
如果嵌套集具有开箱即用的更好的功能将是不错的.
您发现的技巧是从平面集构建树:
>以一组按lft排序的所有节点开始
>第一个节点是根添加它,因为树的根移动到下一个节点
>如果它是前一个节点的子节点(prev.lft和prev.rht之间的lft)将一个子节点添加到树中并向前移动一个节点
>否则将树向上移动一级并重复测试
见下文:
def tree_from_set(set) #set must be in order buf = START_TAG(set[0]) stack = [] stack.push set[0] set[1..-1].each do |node| if stack.last.lft < node.lft < stack.last.rgt if node.leaf? #(node.rgt - node.lft == 1) buf << NODE_TAG(node) else buf << START_TAG(node) stack.push(node) end else# buf << END_TAG stack.pop retry end end buf <<END_TAG end def START_TAG(node) #for example "<li><p>#{node.name}</p><ul>" end def NODE_TAG(node) "<li><p>#{node.name}</p></li>" end def END_TAG "</li></ul>" end