0

@pages我有以下数组

#<Page id: 1, url: "/location1", name: "Information", sort_order: 2, parent_id: nil>
#<Page id: 2, url: "/location2", name: "Information 2", sort_order: 2, parent_id: 4>
#<Page id: 3, url: "/location3", name: "Information 3", sort_order: 1, parent_id: >
#<Page id: 4, url: "/location4", name: "Information 4", sort_order: 1, parent_id: nil>
#<Page id: 5, url: "/location5", name: "Information 5", sort_order: 1, parent_id: 2>
#<Page id: 6, url: "/location6", name: "Information 6", sort_order: 3, parent_id: nil>

我正在尝试用这些页面建立一个导航......注意这只是一个例子我真的有70页类似于这个

我希望最终结果看起来像这样

<ul>
  <li><a href="/location4">Information 4</a>
    <ul>
      <li><a href="/location3">Information 3</a></li>
      <li><a href="/location2">Information 2</a>
        <ul><li><a href="/location5">Information 5</a></li></ul>
      </li>
    </ul>
  </li>
  <li><a href="/location1">Information 1</a></li>
  <li><a href="/location6">Information 6</a></li>
</ul>

因此,如果 li 有另一个子 ul 和 li,则 parent_id 将发出信号,并且排序顺序是 chil li 的排序

我似乎无法围绕我需要如何@pages有效地循环......任何想法......

4

2 回答 2

3

仅从顶层开始Pages,即Pageswhere parent_id == nil,order bysort_order

定义一个children方法,让您获得所有页面,其中parent_id == self.id,按顺序排列sort_order

然后你应该能够做这样的事情:

def build_navigation(pages, html = nil)
  return "" if pages.length == 0

  navigation_html = html || ""
  navigation_html << "<ul>"

  pages.each do |page|
    navigation_html << li_tag(page)
    navigation_html << build_navigation(page.children, navigation_html)
  end

  navigation_html << "</ul>"
end

def li_tag(page)
  "<li><a href='#{page.name}'>#{page.name}</a></li>"
end

build_navigation(parent_pages).html_safe




更新:稍作调整,所以当你只想做一个查询时它可以工作:

def all_pages
  # get all the pages from the DB
end

def parent_pages(pages)
  parents = pages.reject { |page| page.parent_id.nil? }
  sort(parents)
end

def children(parent, pages)
  children = pages.map { |page| page.parent_id == parent.id }
  sort(children)
end

def sort(pages)
  pages.sort { |a, b| a.sort_order <=> b.sort_order }      
end

def build_navigation(pages, html = nil)
  return "" if pages.length == 0

  navigation_html = html || ""
  navigation_html << "<ul>"

  pages.each do |page|
    navigation_html << li_tag(page)
    navigation_html << build_navigation(children(page, all_pages), navigation_html)
  end

  navigation_html << "</ul>"
end

def li_tag(page)
  "<li><a href='#{page.name}'>#{page.name}</a></li>"
end

build_navigation(parent_pages(all_pages)).html_safe
于 2012-11-20T02:19:31.887 回答
1

如果您可以使用额外的宝石,请查看ruby​​tree。请注意,下面的代码示例不考虑您的sort_order属性。但是,您应该能够轻松地编织 sort_order 逻辑。

require 'tree'

class NavBuilder
    def initialize
        @pages     = Page.all
        @root      = Tree::TreeNode.new("SITEMAP", { :id => 0 })
        @processed = []
    end

    def pagetree
        pages_hash = {}
        @pages.each {|page| pages_hash[page.id] = page}

        @pages.each do |page|
            if page.parent_id.nil?
                if @root[page.id.to_s].nil?
                    @root << Tree::TreeNode.new(page.id.to_s, page)
                end 
            else
                parent_node = @root[page.parent_id.to_s]
                if parent_node.nil?
                    inserted = false
                    @root.each do |node| 
                        if page.parent_id == node.content[:id]
                            node << Tree::TreeNode.new(page.id.to_s, page)
                            inserted = true
                        end 
                    end 
                    if !inserted
                        @root << Tree::TreeNode.new(page.parent_id.to_s, pages_hash[page.parent_id]) << Tree::TreeNode.new(page.id.to_s, page)
                    end 
                else
                    parent_node << Tree::TreeNode.new(page.id.to_s, page)
                end 
            end
        end
    end

    def nav_html
        html = "<ul>"
        @root.each do |node|
            if node.content[:id] > 0
                html << html_tags(node.children.size,node)
            end 
        end 
        html << "</ul>"
    end 

    def html_tags(number_of_children,node)
        html = ""
        if !@processed.include?(node.content[:id])
            if number_of_children == 0
                html = "<li><a href=#{node.content.url}>#{node.content.name}</a></li>"
                @processed << node.content[:id]
            else
                html = "<li><a href=#{node.content.url}>#{node.content.name}</a>"
                html << "<ul>"
                node.children.each do |n|
                    html << html_tags(n.children.size,n)
                    @processed << node.content[:id]
                end 
                html << "</ul></li>"
            end     
        end 
        html
    end 
end 

nav = NavBuilder.new
nav.pagetree
puts nav.nav_html

# <ul>
#   <li><a href=/location1>Information 1</a></li>
#   <li><a href=/location4>Information 4</a>
#       <ul>
#           <li><a href=/location2>Information 2</a>
#               <ul><li><a href=/location5>Information 5</a></li></ul>
#           </li>
#           <li><a href=/location3>Information 3</a></li>
#       </ul>
#   </li>
#   <li><a href=/location6>Information 6</a></li>
# </ul>
于 2012-11-20T13:15:24.157 回答