4

我正在尝试编写一个 Rails 辅助方法来将嵌套的哈希转换为嵌套的 HTML 列表。

例如:

{
  :parent => "foo",
  :children => [
    {
      :parent => "bar",
      :children => [
        {
          :parent => "baz",
          :children => []
        }
      ]
    }
  ]
}

应该变成:

<ul>
  <li>foo</li>
  <ul>
    <li>bar</li>
    <ul>
      <li>baz</li>
    </ul>
  </ul>
</ul>

散列可以有任意数量的级别,每个级别可以有任意数量的父级。

请问实现这一目标的最佳方法是什么?

4

2 回答 2

7

您可以使用递归方法将散列渲染到一组嵌套列表。把它放在你的相关助手中:

def hash_list_tag(hash)
  html = content_tag(:ul) {
    ul_contents = ""
    ul_contents << content_tag(:li, hash[:parent])
    hash[:children].each do |child|
      ul_contents << hash_list_tag(child)
    end

    ul_contents.html_safe
  }.html_safe
end
于 2013-02-15T23:11:19.703 回答
1

Zach Kemp 的回答非常有效地解决了这个问题。如果您正在寻找更通用的东西(您不会知道键名的嵌套哈希),就像我一样,以下模块可能会有所帮助(也在https://github.com/sjohnson/auto_hash_display与更多细节):

module HashFormatHelper
  # These methods add classes to the HTML structure that are defined in Bootstrap (and can be defined for other CSS frameworks)
  def format_hash(hash, html = '')
    hash.each do |key, value|
      next if value.blank?
      if value.is_a?(String) || value.is_a?(Numeric)
        html += content_tag(:ul, class: 'list-group') {
          ul_contents = ''
          ul_contents << content_tag(:li, content_tag(:h3, key.to_s.underscore.humanize.titleize), class: 'list-group-item')
          ul_contents << content_tag(:li, value, class: 'list-group-item')

          ul_contents.html_safe
        }
      elsif value.is_a?(Hash)
        html += content_tag(:ul, class: 'list-group') {
          ul_contents = ''
          ul_contents << content_tag(:li, content_tag(:h3, key.to_s.underscore.humanize.titleize), class: 'list-group-item')
          inner = content_tag(:li, format_hash(value), class: 'list-group-item')
          ul_contents << inner

          ul_contents.html_safe
        }
      elsif value.is_a?(Array)
        html += format_array(value)
      else
        Rails.logger.info "Unexpected value in format_hash: #{value.inspect}"
        Rails.logger.info "value type: #{value.class.name}"
      end
    end
    html.html_safe
  end

  def format_array(array, html = '')
    array.each do |value|
      if value.is_a?(String)
        html += content_tag(:div, value).html_safe
      elsif value.is_a?(Hash)
        html += format_hash(value)
      elsif value.is_a?(Array)
        html += format_array(value)
      else
        Rails.logger.info "Unexpected value in format_array: #{value.inspect}"
        Rails.logger.info "value type: #{value.class.name}"
      end
    end
    html
  end
end

此代码还可用于显示 XML,方法是将哈希值设置为等于 Hash.from_xml(your_xml_data),然后将其传递给 format_hash(hash)。

请注意,from_xml 方法可能会去除 XML 标记属性,因此它最适用于没有属性的 XML。

于 2016-04-29T19:08:55.973 回答