我正在尝试创建一个简单的视图助手,但是当我尝试嵌套几个内容标记时,它会抛出
NoMethodError: undefined method `output_buffer=' for
def table_for(list, &proc)
t = Table.new
proc.call(t)
t.render_column(list)
end
class Table
include ActionView::Helpers::TagHelper
attr_accessor :columns, :block
def initialize
@columns = Array.new
end
def col(name)
@columns << name
end
def render_column(list)
content_tag :table do
list.each do |c|
content_tag :td, c
end
end
end
end
任何有关错误的提示?我也看到有一个XmlBuilder对我的目的更好吗?
答案 0 :(得分:69)
ActionView :: Base内置了Context模块,它提供了方法output_buffer()和output_buffer =()。
所以你可以通过让你的班级来解决你的问题:
include ActionView::Context
甚至更简单:
attr_accessor :output_buffer
答案 1 :(得分:2)
我认为在3.0中有一些变化,但在以前的版本中,诀窍是通过self
:
def table_for(list, &proc)
Table.new(self)
# ...
def initialize(binding)
@binding = binding
#...
def render_column
@binding.content_tag :table do
# ...
end
end
我不确定这是否仍然是在rails 3中完成的。
修复ordere以使代码工作的另一个方法是将内部content_tag的输出保存在某处,与each
一样,生成内容然后将其丢弃。其中一个可能的解决方案:
def render_column(list)
@binding.content_tag :table do
list.inject "" do |out, c|
out << @binding.content_tag(:td, c)
end.html_safe
end
end
答案 2 :(得分:-3)
在Nested content_tag throws undefined method `output_buffer=` in simple helper的帮助下,我最终获得了受Formtastic API启发的以下解决方案。
<%= table_for(@users) do |t| %>
<% t.col :name %>
<% t.col :email %>
<% t.col :test, :value => lambda { |u| u.email }, :th => 'Custom column name' %>
<% t.col :static, :value => 'static value' %>
<% end %>
直接使用output_buffer并且可能重新发明轮子,代码看起来像
module ApplicationHelper
def table_for(list, &block)
table = Table.new(self)
block.call(table)
table.show(list)
end
class Column
include ActiveSupport::Inflector
attr_accessor :name, :options
def initialize(name, options = {})
@name = name
@options = options
end
def td_value(item)
value = options[:td]
if (value)
if (value.respond_to?('call'))
value.call(item)
else
value
end
else
item[name]
end
end
def th_value
options[:th] ||= humanize(name)
end
end
class Table
include ActionView::Helpers::TagHelper
attr_accessor :template, :columns
def initialize(temp)
@columns = Array.new
@template = temp
end
def col(name, options = {})
columns << Column.new(name, options)
end
def show(list)
template.content_tag(:table) do
template.output_buffer << template.content_tag(:tr) do
columns.collect do |c|
template.output_buffer << content_tag(:th, c.th_value)
end
end
list.collect do |item|
template.output_buffer << template.content_tag(:tr) do
columns.collect do |c|
template.output_buffer << template.content_tag(:td, c.td_value(item))
end
end
end
end
end
end
end