helper类中每个块内的content_tag

时间:2012-11-28 22:54:12

标签: ruby-on-rails erb

我想在rails中创建一个视图助手,它允许使用如下语法:

<%= some_fancy_list @items do |h| %>
  <%= h.rows :class => "whatever" |item| %>
    <td><= item.id %>
  <% end %>
<% end %>

我已经构建了这个(这是一个简化版本)

的效果
def some_fancy_list(items, &block)
  h = InternalHelper.new(:items => items)
  content_tag(:table) { block.call(h) }
end

class InternalHelper
  include ActionView::Helpers::TagHelper
  include ActionView::Context

  def initialize
    ...
  end

  def rows(options = {}, &block)
    content_tag(:tbody) do
      @items.each do |item|
        content_tag(:tr, options) do
          block.call(item) if block_given?
        end
      end
    end
  end
end

问题是它输出的HTML并不完全符合我的预期。

<table>
<td>1</td>
<td>2</td>
<td>3</td>
<tbody></tbody>
</table>

<tr>完全丢失,<td>的阻止内容甚至不在<tbody>标记内。

我在StackOverflow上发现了这个问题:Loop & output content_tags within content_tag in helper并尝试使用concat但是我收到以下错误:

undefined method `concat'

我猜这与.each中丢失的上下文有关,但我对如何处理它感到茫然。

1 个答案:

答案 0 :(得分:0)

问题似乎在于使用了最初调用视图助手的上下文之外的另一个类。解决方案包括删除Content和TextHelper的包含,然后在类上创建一个代理方法,该方法链接回调用该类的上下文。

# self is passed into the helper class:
h = InternalHelper.new(self, :items => items)

# then the helper class makes a proxy back to that parent instance
class InternalHelper
  # removed these:
  # include ActionView::Helpers::TagHelper
  # include ActionView::Context

  # added this:
  def content_tag(*args, &block)
    @parent.content_tag(*args, &block)
  end
end

这基本上使得content_tag从相同的上下文中调用,就好像它在视图助手中一样,并且它以在InternalHelper上实现功能时变得不可见的方式来实现类。