ruby on rails 3 - link_to - Content_tag anidado arroja el método indefinido `output_buffer=` en un simple ayudante
content_tag link_to rails (3)
ActionView :: Base ha incorporado en él el módulo de contexto, que proporciona los métodos output_buffer () y output_buffer = ().
Así que puedes resolver tu problema haciendo que tu clase haga:
include ActionView::Context
O incluso más simplemente:
attr_accessor :output_buffer
Estoy intentando crear un ayudante de visualización simple, pero tan pronto como intente anidar un par de etiquetas de contenido, se lanzará
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
¿Alguna pista de lo que está mal? También he visto que hay un XmlBuilder que es mejor para mi propósito?
Con la ayuda de Nested content_tag lanza el método indefinido `output_buffer =` en un simple ayudante , terminé con la siguiente solución inspirada en la API para Formtastic.
<%= 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 %>
Usando el output_buffer directamente y probablemente reinventando la rueda, el código parece
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
Creo que hubo algunos cambios al respecto en 3.0, pero en versiones anteriores, el truco era pasar self
:
def table_for(list, &proc)
Table.new(self)
# ...
def initialize(binding)
@binding = binding
#...
def render_column
@binding.content_tag :table do
# ...
end
end
No estoy seguro si esto sigue siendo así como se hace en los rieles 3.
Otra cosa que se debe corregir para que el código funcione es guardar la salida del content_tag interno en algún lugar, ya que con each
contenido se genera y luego se descarta. Una de las posibles soluciones:
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