복붙노트

[SQL] 실제 HTML 트리로 중첩 된 세트에서 모든 레코드를 렌더링하는 방법

SQL

실제 HTML 트리로 중첩 된 세트에서 모든 레코드를 렌더링하는 방법

내 레일 프로젝트에 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에서 허용 물론이다) 여러 루트 노드가.

지금, 나는 구조와 같은 올바르게 정렬 된 트리에서 해당 고객의 모든 범주를 렌더링 할 : 예를 들어 중첩 된

    태그. 이것은 너무 어렵지 않을 것이다 그러나 나는 그것이 효율적으로해야 (적은 SQL은 더 나은 쿼리).

    업데이트 : (- node.lft - 1 node.rgt) / 2 NUMBER_OF_CHILDREN =이 더욱 SQL 쿼리없이 트리의 특정 노드에 대한 아이들의 수를 계산하는 것이 가능하다는 것을 알아 냈다. 이 문제가 해결되지 않고 도움이 될 증명할 수 있습니다.

    해결법

    1. ==============================

      1.중첩 된 세트가 더 나은했다 밖으로 상자의 기능 그것을하지 않는다면 그것은 좋은 것입니다.

      중첩 된 세트가 더 나은했다 밖으로 상자의 기능 그것을하지 않는다면 그것은 좋은 것입니다.

      당신이 발견 한 것처럼 트릭은 평평한 세트에서 트리를 구축하는 것입니다 :

      아래 참조 :

      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 
      
    2. ==============================

      2.나는 최근에 PHP에 대한 비슷한 질문 (중첩 된 세트 == 수정 전순 트리 탐색 모델) 대답했다.

      나는 최근에 PHP에 대한 비슷한 질문 (중첩 된 세트 == 수정 전순 트리 탐색 모델) 대답했다.

      기본 개념은 노드가 이미 주문하고 하나 개의 SQL 쿼리를 이용하여 깊이 표시와 함께 얻을 수 있습니다. 쉽게 루비이 변환하는 것, 그래서 거기에서 그것은 루프 또는 재귀를 통해 출력을 렌더링 단지 질문입니다.

      나는에서 awesome_nested_set 플러그에 익숙하지 해요,하지만 중첩 된 세트를 다루는 꽤 표준 작업 / 필요가 그대로 이미 주석 깊이, 주문 결과를 얻을 수있는 옵션이 포함되어있을 수 있습니다.

    3. ==============================

      3.2009년 9월 멋진 중첩 된 세트가 포함되어 있기 때문에 특별한 방법은이 작업을 수행합니다 : https://github.com/collectiveidea/awesome_nested_set/commit/9fcaaff3d6b351b11c4b40dc1f3e37f33d0a8cbe

      2009년 9월 멋진 중첩 된 세트가 포함되어 있기 때문에 특별한 방법은이 작업을 수행합니다 : https://github.com/collectiveidea/awesome_nested_set/commit/9fcaaff3d6b351b11c4b40dc1f3e37f33d0a8cbe

      이 방법은 별도의 데이터베이스 쿼리를 필요로하지 않기 때문에 수준을 호출하는 것보다 훨씬 더 효율적이다.

      예 : Category.each_with_level (Category.root.self_and_descendants) 할 | 오, 레벨 |

    4. ==============================

      4.당신은 자신을 재귀 적으로 호출하는 부분을 렌더링해야합니다. 이 같은:

      당신은 자신을 재귀 적으로 호출하는 부분을 렌더링해야합니다. 이 같은:

      # customers/show.html.erb
      <p>Name: <%= @customer.name %></p>
      <h3>Categories</h3>
      <ul>
        <%= render :partial => @customer.categories %>
      </ul>
      
      # categories/_category.html.erb
      <li>
        <%= link_to category.name, category %>
        <ul>
          <%= render :partial => category.children %>
        </ul>
      </li>
      

      이 레일 2.3 코드입니다. 당신은 경로를 호출하여 명시 적으로 그 전에 부분의 이름을 지정해야합니다.

    5. ==============================

      5._tree.html.eb

      _tree.html.eb

      @set = Category.root.self_and_descendants
      <%= render :partial => 'item', :object => @set[0] %>
      

      _item.html.erb

      <% @set.shift %>
      <li><%= item.name %>
      <% unless item.leaf? %>
      <ul>
        <%= render :partial => 'item', :collection => @set.select{|i| i.parent_id == item.id} %>
      </ul>
      <% end %>
      </li>
      

      당신은 또한 자신을 정렬 할 수 있습니다 :

        <%= render :partial => 'item', :collection => @set.select{|i| i.parent_id == item.id}.sort_by(&:name) %>
      

      하지만 경우에 당신은이 줄을 제거해야합니다 :

      <% @set.shift %>
      
    6. ==============================

      6.나는 때문에 그것을 위해 작성되었습니다 루비의 이전 버전의 허용 대답을 작동시킬 수 없습니다, 나는 가정한다. 다음은 나를 위해 일하는 솔루션입니다 :

      나는 때문에 그것을 위해 작성되었습니다 루비의 이전 버전의 허용 대답을 작동시킬 수 없습니다, 나는 가정한다. 다음은 나를 위해 일하는 솔루션입니다 :

      def tree_from_set(set)
          buf = ''
      
          depth = -1
          set.each do |node|
              if node.depth > depth
                  buf << "<ul><li>#{node.title}"
              else
                  buf << "</li></ul>" * (depth - node.depth)
                  buf << "</li><li>#{node.title}"
              end
      
              depth = node.depth
          end
      
          buf << "</li></ul>" * (depth + 1)
      
          buf.html_safe
      end
      

      그것은 선택적인 깊이 정보를 이용하여 간단합니다. (이 방법의 장점은 잎의 전체 구조로 설정 입력에 대한 필요가 없다는 것입니다.)

      깊이없이 더 복잡한 솔루션은 보석의 GitHub의 위키에서 찾을 수 있습니다 :

      https://github.com/collectiveidea/awesome_nested_set/wiki/How-to-generate-nested-unordered-list-tags-with-one-DB-hit

    7. ==============================

      7.어쩌면 조금 늦게하지만 난 closure_tree 보석 중첩 hash_tree 방법에 따라 awesome_nested_set에 대한 내 솔루션을 공유하고 싶습니다 :

      어쩌면 조금 늦게하지만 난 closure_tree 보석 중첩 hash_tree 방법에 따라 awesome_nested_set에 대한 내 솔루션을 공유하고 싶습니다 :

      def build_hash_tree(tree_scope)
        tree = ActiveSupport::OrderedHash.new
        id_to_hash = {}
      
        tree_scope.each do |ea|
          h = id_to_hash[ea.id] = ActiveSupport::OrderedHash.new
          (id_to_hash[ea.parent_id] || tree)[ea] = h
        end
        tree
      end
      

      LFT으로 주문한 범위와이 의지 작업

      사용 도우미보다 그것을 렌더링합니다 :

      def render_hash_tree(tree)
        content_tag :ul do
          tree.each_pair do |node, children|
            content = node.name
            content += render_hash_tree(children) if children.any?
            concat content_tag(:li, content.html_safe)
          end
        end
      end
      

from https://stackoverflow.com/questions/1372366/how-to-render-all-records-from-a-nested-set-into-a-real-html-tree by cc-by-sa and MIT license