0

I have a very slow ruby on rails page. It is displaying an hierarchical, unordered list. It was slow, because it was building the list through recursive SQL calls, which was stupid to start with. I've figured out how to get the SQL to give me the hierarchy. Now that I can get the required information through a single SQL call, I'm having issues building the resulting HTML.

This is what my SQL is returning. Each row is a different record, two columns 'id', and 'path'. I can easily break apart the different items by doing row.path.split to get something like ['A', 'E', 'F']. I just can't figure out the best way to manage the opening and closing tags of the list.

     ID   |  PATH
01. Root  |  Root
02. A     |  Root A
03. B     |  Root B
04. C     |  Root B C
05. D     |  Root B D
06. E     |  Root A E
07. F     |  Root A E F
08. G     |  Root B D G
09. H     |  Root B C H
10. I     |  Root B D I
11. J     |  Root B D G J
12. F     |  Root B C H F
13. K     |  Root B D I K
14. L     |  Root B D I L
15. F     |  Root B D I L F

And I need the unordered list to look something like this:

format of unordered list

Source html of the above screenshot

4

2 回答 2

1

首先,如果数据很大,我建议简化查询,只返回带有叶子数据的行。您的示例数据中只有 5 个,其中包含您需要的所有信息。

无论哪种情况,此代码都会生成所需的 html:

#!/usr/bin/env ruby

$h = Hash.new
DATA.each do |path| # replace this line with the SQL query
  hash = $h
  path.split(' ').each do |e|
    if hash.has_key?(e)
      hash = hash[e]
    else
      hash = hash[e] = Hash.new
    end
  end
end

def hash_to_string( h )
  return if h.empty?
  list_items = h.map { |k,v| "<li>#{k}#{hash_to_string(v)}</li>\n" }
  return "\n<ul>\n#{list_items.join}</ul>";
end

puts hash_to_string( $h )

__END__
Root
Root A
Root B
Root B C
Root B D
Root A E
Root A E F
Root B D G
Root B C H
Root B D I
Root B D G J
Root B C H F
Root B D I K
Root B D I L
Root B D I L F

我建议先直接运行这个脚本,看看它是否生成了预期的 html。然后调整它以符合您的需求;主要是DATA.each ...线路。

于 2013-09-06T19:25:17.423 回答
1

哈希构建的递归版本,DATA假设与@Matt 的答案完全相同,并且生成的哈希将是相同的,因此hash_to_string(h)工作方式相同。

class Hash
  def merge_path path 
    return if path == []
    first, rest = path.first, path[1..-1]
    self[first] ||= {}
    self[first].merge_path rest
  end
end

hash = {}
DATA.lines.map(&:split).each { |path| hash.merge_path path }

通常,在重新打开和扩展核心和标准库类时应该小心。

于 2013-09-06T20:00:48.947 回答