在Rails

时间:2017-02-02 09:45:44

标签: ruby-on-rails ruby-on-rails-4 html-table

我正在尝试将Rails 2.3应用程序更新为更新的Rails版本(4/5) 我有一个方法,使用列表作为输入打印一个html表,调用者可以自定义行的显示。我还搜索了一些类似的东西,但它们并没有我需要的所有要求。所以我必须做这项工作。代码是

  def model_table_2(collection, headers, options = {}, &proc)
    options.reverse_merge!({
        :id           => nil,
        :class        => nil,
        :style        => nil,
        :placeholder  => 'Empty',
        :caption      => nil,
        :summary      => nil,
        :footer       => nil
      })
    placeholder_unless !collection.empty?, options[:placeholder] do
      html_opt = options.slice(:id, :class, :style, :summary)
      content_tag(:table, html_opt) do
        table_sections = []
        table_sections << content_tag(:caption, options[:caption]).to_s if options[:caption]
        table_sections << content_tag(:thead, 
          content_tag(:tr,
              headers.collect { |h| 
                concat(content_tag(:th, h))
              }
            )
        )
        if options[:footer]
          table_sections << content_tag(:tfoot,
            content_tag(:tr, content_tag(:th, concat(options[:footer]), :colspan => headers.size)) 
          )
        end
        table_sections << content_tag(:tbody, 
          collection.each_with_index.collect do |row, row_index|
            concat(
              proc.call(row, cycle('odd', 'even'), row_index)
            )
          end.join
        )
        table_sections.join
      end
    end
  end

  def placeholder(message = t('general.empty'), options = {}, &proc)
    # set default options
    o = { :class => 'placeholder', :tag => 'p' }.merge(options)

    # wrap the results of the supplied block, or just print out the message
    if proc
      t = o.delete(:tag)
      concat tag(t, o, true), proc.binding
      yield
      concat "</#{t}>", proc.binding
    else
      content_tag o.delete(:tag), message, o
    end
  end

  def placeholder_unless(condition, *args, &proc)
    condition ? proc.call : concat(placeholder(args), proc.binding)
  end

在视图文件中我称之为:

<% table_cols = ["No.", "Name"] %>
<% obj_list = [{active: true, name: 'First'}, {active: true, name: 'Second'}, {active: false, name: 'Last'}, nil] %>
<%= model_table_2(obj_list, table_cols, {:class=>'table table-bordered', :caption=>'Model Table Test', :footer=>'The Footer'}) do |record, klass, row_index| -%>
  <% if !record.nil? then %>
    <% content_tag :tr, :class => klass + (record[:active] ? '' : ' text-muted') do -%>
        <td><%= row_index+1 -%></td>
        <td><%= record[:name] %></td>
    <% end %>
  <% else %>
    <% content_tag :tr, :class => klass do -%>
        <td style="text-align:center;">*</td>
        <td>render form</td>
    <% end %>
  <% end %>
<% end %>

但输出并不是我所期望的:

<table class="table table-bordered">
   <th>No.</th>
   <th>Name</th>
   The Footer
   <tr class="even">
      <td>1</td>
      <td>First</td>
   </tr>
   <tr class="odd">
      <td>2</td>
      <td>Second</td>
   </tr>
   <tr class="even text-muted">
      <td>3</td>
      <td>Last</td>
   </tr>
   <tr class="odd">
      <td>*</td>
      <td>render form</td>
   </tr>
</table>

如您所见,某些标记遗失了,例如captiontheadtbodytfoot。我猜是因为content_tag调用是嵌套的。我之前没有使用table_sections数组,但它也没有工作。

此外,当列表为空时我出错,代码转到placeholder...方法。

1 个答案:

答案 0 :(得分:1)

这是一个奇怪的content_tag怪癖,但如果你嵌套它们,你需要use a concat on each return in the inner tags。否则,您只需获取最后返回的字符串,内部标记就会消失在以太网中。可悲的是,根据我的经验,我发现复杂的嵌套不值得进入辅助方法。

也许,更好的方法是使用装饰器模式,rails部分或使用类似cells gem之类的东西来干掉html。