我的数组@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,并且排序顺序是chil li的排序,那么parent_id将发出信号
我似乎无法将我的大脑包裹在如何有效地循环@pages
......任何想法......
答案 0 :(得分:3)
仅从顶级Pages
开始,即Pages
其中parent_id == nil
,按sort_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
答案 1 :(得分:1)
如果您可以使用额外的宝石,请查看rubytree。请注意,下面的代码示例不考虑您的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>