¿Cómo crear un asistente de bloque propio con dos o más hijos anidados?

Me gustaría algo anidado así en mis puntos de vista:

<%= helper_a do |ha| %>
  Content for a
  <%= ha.helper_b do |hb| %>
    Content for b
    <%= hb.helper_c do |hc| %>
      Content for c
      ... and so on ...
    <% end %>
  <% end %>
<% end %>

Para obtener, por ejemplo, esto:

<tag_a>
  Content for a
  <tag_b class="child_of_tag_a">
    Content for b
    <tag_c class="nested_child_of_tag_a child_of_tag_b">
      Content for c
    </tag_c>
  </tag_b>
</tag_a>

Esto significa que cada nivel tiene acceso a alguna información del nivel anterior (por eso son métodos anidados y no completamente autónomos)

Sé cómo crear un ayudante simple:

def helper_a(&block)
  content = capture(&block)
  content_tag :tag_a, content
end

Y sé que puedo pasar mis argumentos a la capture para usarlos en la vista, así que algo como esto para mejorar la |ha| de mi ejemplo

def helper_a(&block)
  content = capture(OBJECT_HERE, &block)
  content_tag :tag_a, content
end

Pero donde defino esto OBJECT_HERE, especialmente la clase para él, y ¿cómo puede continuar esto anidado con múltiples niveles capturando cada bloque?

preguntado el 27 de agosto de 11 a las 23:08

¿Realmente necesitas poner la información de anidamiento en clases html? De su ejemplo, no me molestaría en usar "tag_a tag_b {propiedad: valor}" en CSS o "$ ('tag_a tag_b')" en jQuery. ¿Podría decirnos si necesita hacer algo más que el estilo CSS y / o la manipulación de Javascript? -

Las clases adicionales agregadas son solo para el ejemplo aquí, con eso tienes razón. Puede haber otras cosas que cambien dependiendo de la "información anidada". Pero parece que estoy tratando de hacerlo demasiado complicado de todos modos si necesito más de un nivel anidado, así que debería pensar en el diseño de mi aplicación. -

1 Respuestas

Se me ocurrieron un par de soluciones, pero estoy lejos de ser un experto en el sistema de plantillas Rails.

El primero está usando una variable de instancia:

def helper_a(&block)
  with_context(:tag_a) do
    content = capture(&block)
    content_tag :tag_a, content
  end
end

def helper_b(&block)
  with_context(:tag_b) do
    content = capture(&block)
    content_tag :tag_b, content
  end
end

def helper_c(&block)
  with_context(:tag_c) do
    content = capture(&block)
    content_tag :tag_c, content
  end
end

def with_context(name)
  @context ||= []
  @context.push(name)
  content = yield
  @context.pop
  content
end

que se usa de esta manera:

<%= helper_a do %>
  Content for a
  <%= helper_b do %>
    Content for b
    <%= helper_c do %>
      Content for c
      ... and so on ...
    <% end %>
  <% end %>
<% end %>

Y la otra solución, que pasa el contexto en cada paso:

def helper_a(context = [], &block)
  context = capture(context.push(:tag_a), &block)
  content_tag(:tag_a, content)
end

def helper_b(context = [], &block)
  context = capture(context.push(:tag_b), &block)
  content_tag(:tag_b, content)
end

def helper_c(context = [], &block)
  context = capture(context.push(:tag_c), &block)
  content_tag(:tag_c, content)
end

que se usa de esta manera:

<%= helper_a do |context| %>
  Content for a
  <%= helper_b(context) do |context| %>
    Content for b
    <%= helper_c(context) do |context| %>
      Content for c
      ... and so on ...
    <% end %>
  <% end %>
<% end %>

Pero realmente desaconsejaría el uso de cualquiera de estas soluciones si todo lo que está haciendo es estilo CSS y / o manipulación de Javascript. Realmente complica a los ayudantes, es probable que introduzca errores, etc.

Espero que esto ayude.

Respondido 28 ago 11, 19:08

Gracias, esto parece dos formas de hacerlo. Hace unas horas pensé en una solución similar con variables de instancia. Y llegué a la conclusión de pensar por qué el diseño de mi aplicación necesita tantos niveles anidados y hacer algo en contra de eso en lugar de intentar anidar como el infierno ;-) Pero si todavía tengo que hacerlo, usaré uno de estos. - Markus

Hago lo mismo todo el tiempo, golpeándome la cabeza contra una solución de ingeniería excesiva porque tenía algo en mente, y luego retrocediendo y diciéndome a mí mismo "no necesito toda esta mierda" ;-) - Benoit Garret

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.