如何将嵌套集中的所有记录呈现为真正的html树

Chr*_*ssl 8 ruby sql activerecord ruby-on-rails nested-sets

我正在使用awesome_nested_set我的Rails项目中的插件.我有两个看起来像这样的模型(简化):

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
Run Code Online (Sandbox Code Playgroud)

数据库中的树按预期构造.的所有值parent_id,lft以及rgt是否正确.树有多个根节点(当然允许进入awesome_nested_set).

现在,我想在一个正确排序的树中呈现给定客户的所有类别,例如结构:例如嵌套<ul>标签.这不会太难,但我需要它才能有效(sql查询越少越好).

更新:想出可以在没有进一步SQL查询的情况下计算树中任何给定节点的子节点数:number_of_children = (node.rgt - node.lft - 1)/2.这并不能解决问题,但可能会有所帮助.

Joh*_*ler 7

如果嵌套集具有开箱即用的更好的功能将是不错的.

您发现的技巧是从平面集构建树:

  • 从一组按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 
Run Code Online (Sandbox Code Playgroud)


Hen*_*pel 5

我最近回答了一个关于php类似问题(嵌套set == modified preorder tree traversal model).

基本概念是通过一个SQL查询获取已经排序的节点和深度指示器.从那里它只是通过循环或递归渲染输出的问题,因此应该很容易将其转换为ruby.

我不熟悉的awesome_nested_set插件,但它可能已经包含一个选项来获得注释的深度,有序的结果,因为它是嵌套集时,一个非常标准的操作/需要.


Syt*_*dij 5

自2009年9月以来,令人敬畏的嵌套集包括一个特殊的方法来执行此操作:https: //github.com/collectiveidea/awesome_nested_set/commit/9fcaaff3d6b351b11c4b40dc1f3e37f33d0a8cbe

此方法比调用级别更有效,因为它不需要任何其他数据库查询.

示例:Category.each_with_level(Category.root.self_and_descendants)do | o,level |