10: ACTION VIEW: Action View - LPC-Ltda/Ruby-on-Rails GitHub Wiki

El muy poderoso y el muy estúpido tienen una cosa en común. En lugar de alterar sus puntos de vista para adaptarse a los hechos, si alteran los hechos para encajar sus puntos de vista ... lo que puede ser muy incómodo si quieres pasar a ser uno de los hechos que se debe alterar. -Doctor Who

Los controladores son el esqueleto y la musculatura de su aplicación Rails. En cuyo caso, los modelos forman el corazón y la mente, y sus templates de view (basados en Action View, el tercer mayor componente de Rails) es la piel de su aplicación -la parte visible para el mundo exterior.

Action View es la API de Rails para reunir los componentes visuales de su aplicación -a saber, el HTML y contenido asociado que será rendereado en el browser de web cuando quiera que alguien use su aplicación Rails. Realmente, en este bravo nuevo mundo de recursos REST, Action View esta involucrado en generar casi cualquier tipo de salida que usted genere.

Action View contiene un sistema completo de templates basado en una librería de Ruby llamada ERb. Toma data preparada por el nivel de controlador y la intercala con el código de la vista para crear un nivel de presentación para el usuario final. Esta es una de las primeras cosas que usted aprende de Rails y parte de la librería estándar de Ruby. Yo prefiero mucho más una solución de templates llamada Haml la que he usado en este libro para los ejemplos. Yo pienso que Haml es mucho más superior que Erb por ello no cubre ERb para nada.

En este capítulo cubrimos los fundamentos del framework Action View, desde el uso efectivo de parciales a la carga al aumento significativo de rendimiento via el uso del almacenamiento en cache. Si usted necesita aprender Haml, lo cubrimos en detalle en el Capítulo 12, "Haml".

##10.1 Layouts y Templates

Rails tiene convenciones simples para el uso de templates relacionada con la ubicación de templates en los directorios de proyecto de Rails.

El directorio app/views contiene subdirectorios correspondientes al nombre del controlador en su aplicación. Dentro de cada subdirectorio de vista de controlador, usted pone un template cuyo nombre debe coincidir con su acción correspondiente.

El directorio especial app/views/layout contiene templates layout destinado a ser contenedores reusables para sus vistas. De nuevo, convenciones de nombre son usadas para determinar cuales templates renderear, except que esta vez es el nombre del controlador el que es usado para la coincidencia.

###10.1.1 Convenciones de nombres de archivo de templates

El nombre de archivo de un template en Rails trae consigo mucho significado. Sus partes, delimitadas por puntos, corresponden a la siguiente información:

  • Nombre (usualmente mapeados a la acción)
  • Locale (opcional)
  • Tipo de contenido
  • Template engine(s)
  • Variant (opcional, nuevo en Rails 4.1)

###10.1.2 Layouts

Action View decide que layout renderear basado en la herencia jerárquica de los controladores que están siendo ejecutados. La mayoría de las aplicaciones Rails tienen un archivo application.html.haml en su directorio layout. Este comparte su nombre con el ApplicationController, el cual es típicamente extendido por todos los otros controladores en la aplicación; por lo tanto, es elegido como el layout por defecto para todas las vistas.

Es elegido, a menos, por supuesto, que un template de layout más específico este en el lugar, pero frecuentemente usar sólo un template para toda la aplicación, como el simple mostrado en el Listado 10.1.

!!! 5
%html
  %head
    %meta{ charset: 'utf-8' }
    %title TRW4 Time and Expenses Sample Application
    = csrf_meta_tag
    = stylesheet_link_tag 'application', media: 'all'
  %body
    = yield

###10.1.3 Contenido producido

La palabra clave del lenguaje Ruby yield es puesta para la colaborar en la construcción de templates de layout y acción. Note el uso de yield al final del template de layout:

%body
  = yield

En este caso, yield por si mismo es un mensaje especial al sistema de rendereo. Marca el lugar donde insertar la salida del rendereo de la acción, la cual es generalmente el template correspondiente a la acción.

Usted puede agregar lugares extras en su layout donde usted desea poder hacer un yield de contenido para incluir invocaciones de yield adicionales -sólo asegúrese que usted pasa un único identificador como argumento. Un buen ejemplo es un layout que tiene contenido lateral a la derecha e izqueirda (simplificado por supuesto):

%body
  .left.sidebar
    =yield :left
  .content
    = yield 
  .right.sidebar
    = yield :right

El div .content recibe el template marcado principal generado. Pero cómo obtiene Rails contenido para los laterales de la derecha e izquierda? Es fácil: sólo use el método content_for donde quiera en el código de su template. Yo usualmente lo pongo en la cima del template así esto obvio.

- content_for :left do
  %h2 Navigation
  %ul
    %li ...

- content_for :right do
  %h2 Help
  %p Lorem ipsum dolor sit amet, consectetur adipisicing elit...

%h1 Page Heading
%p ...

Junto a los laterales y otros tipos de bloques visibles de contenido, Sugiero hacer un yield del contenido adicional agregado al elemento HEAD de su página, como se muestra en el Listado 10.2.

Listado 10.2 Produciendo contenido adicional de Head

!!! 5
%html
  %head
    %meta{ charset: 'utf-8' }
    %title TRW4 Time and Expenses Sample Application
    = csrf_meta_tag
    = stylesheet_link_tag 'application', media: 'all'
    = yield :head
  %body
    = yield

Un yield en el HEAD es también una buena técnica para incluir tags meta específicos de una página, como los requeridos por Facebook Open Graph.

###10.1.4 Salida condicional

Uno de los idiomas más comunes que usará cuando codifique vistas Rails es la salida de contenido condicional a la vista. La forma más elemental de controlar salidas condicionales es usar la instrucción if.

- if show_subtitle?
  %h2= article.subtitle

Muchas veces usted puede usar la condición if en línea para abreviar su código, ya que el = de salida no se preocupa si usted lo alimenta con un valor nil. Solo agregue una condición if al final de la instrucción:

%h2= article.subtitle if show_subtitle?

Por supuesto, hay un problema con el ejemplo anterior. La instrucción if en una línea separada eliminará completamente el tag <h2> pero el segundo ejemplo en línea no.

Hay un par de formas de tratar con el problema y mantenerlo en una línea. Primero, hay una solución fea que ocasionalmente veo en las aplicaciones Rails, la cual es la única razón por la cual la menciono aqui!

= "<h2>#{h(article.subtitle)}</h2>".html_safe if show_subtitle?

Una solución más elegante involucra el método helper content_tag de Rails, pero admitimos que la solución en una línea es probablemente infereior a la equivalente en dos líneas en este caso.

content_tag('h2', article.subtitle) if show_subtitle?

Los métodos helper, tanto los incluidos en Rails como content_tag como los que puede escribir por usted mismo, son su herramienta principal para construir templates de vistas elegantes. Los helpers serán cubiertos en extenso el en Capítulo 11, "Todo acerca de los Helpers".

###10.1.5 Decent Exposure

Hemos visto como los layouts y los bloques de producción (yield) de contenido funcionan, pero aparte de esto, cómo puede la data ir desde el nivel del controlador a la vista? Durante la preparación del template, las variables de instancias seteadas durante la ejecución de la acción del controlador, serán copiadas como variables de instancia del contexto del tamplate. Aunque esta es la forma estándar expuesta en la documentación Rails, compartir el estado via variables de instancia en los controladores promueve una estrecha emparejamiento con las vistas. La Decent Exposure gem1 de Stephen Caudill provee una manera declarativa de exponer una interface del estado que los controladores contienen, de este modo decrece el emparejamiento y mejora la posibilidad de probar y el diseño general.

Cuando se invoca, la macro expose crea un método con un nombre dado, evalúa el bloque provisto y memoriza el resultado. Este método es entonces declarado como un helper_method para que las vistas tengan acceso a él y se hace no ruteable como acción. Cuando ningún bloque es proporcionado, expose intenta intuir que recurso usted desea adquirir.

# Timesheet.find(params[:timesheet_id] || params[:id])
expose(:timesheet)

Como el ejemplo muestra, el símbolo pasado es usado para adivinar el nombre de la clase del objeto que usted desea encontrar -útil ya que casi todos los controladores usan este tipo de código en las acciones show, edit, y destroy.

En un escenario un poco más complicado, usted puede necesitar encontrar una instancia de un objeto que no se mapea limpiamente a un método find simple.

expose(:timesheet) { client.timesheets.find(params[:id]) }

En el paradigma del controlador REST, usted se encuentra usando esto mismo el las acciones show, update y destroy de los recursos anidados.

Cuando el código se ha hecho lo suficientemente largo para sobrepasar una única línea (pero aún no es apropiado extraerlo dentro de un método de modelo), use un estilo de block `do... end, como en el siguiente ejemplo que usa los tres estilos:

expose(:client)

expose(:timesheet) { client.timesheet.find(params[:id]) }

expose(:timesheet_approval_presenter) do
  TimesheetApprovalPresenter.new(timesheet, current_user)
end

El ejemplo previo también muestra cómo las declaraciones expose pueden depender la una de la otra. De hecho, el uso apropiado de expose debe eliminar la mayoría del código que mira el modelo desde las acciones de controlador actual.

En Hashrocket, el uso de Decent Exposure ha provisto tanto beneficio que ha reemplazado el uso directo da variables de instancia en controladores y vistas. Los métodos helper creados por la macro expose se refieren directamente en la vista.

###10.1.6 Variables de instancia estándar

Más que sólo variables de instancia desde el controlador son copiadas sobre el template. No es una buena idea depender de algunos de los siguientes objetos directamente, y especialmente no los use para operaciones de data. Otros son una parte estándar de la mayoría de las aplicaciones Rails.

10.1.6.1 assigns

Desea ver todo lo que viene desde el borde controlador-vista? Throw = debug(assign) dentro de su template y heche una mirada a su salida. El atributo assigns es escencialmente interno de Rails, y usted no debe usarlo directamente en su código de producción.

10.1.6.2 base_path

Ruta del sistema de archivos local que apunta al directorio base de su aplicación donde los templates han sido puestos.

10.1.6.3 controller

La instancia de controlador actual se hace disponible vía controller, antes que se salga del ámbito final del proceso de requerimientos. Usted puede tomar ventaja del conocimiento del controlador de su nombre (vía el atributo controller_name) y la acción que ha sido recién realizada (vía el atributo action_name) con el fin de estructurar su CSS más eficazmente.

%body{ class: "#{controller.controller_name} #{controller.action_name}" }

Esto puede resultar en un tag BODY que luce como este, dependiendo de la acción ejecutada:

<body class="timesheet index">

Nota: Usted puede replicar la funcionalidad en el ejemplo previo usando el método helper de Haml page_class.

%body{ class: page_class }

Tenemos la esperanza que usted ya sepa que la C en CSS está por cascading, lo cual se refiere al hecho de que los nombres de clase caen en cascada hacia abalo del árbol de elementos en su código etiquetado (markup) y están disponibles para la creación de reglas. El truco es incluir automáticamente los nombres de controlador y acción como nombres de clase de su elemento body para que usted pueda usarlos para personalizar el look and feel de la página muy flexiblemente al final de su ciclo de desarrollo. Por ejemplo, aquí está el cómo usted debe usar la técnica de variar el background de los elementos encabezados dependiendo de la ruta del controlador en CSS:

body {
  .timesheet .header {
    background: image_url(timesheet-bg.png) no-repeat left top;
  }

  .expense_reports .header {
    background: image_url(expense-report-bg.png) no-repeat left top;
  }
}

10.1.6.4 cookies

La variable cookie es un hash que contiene las cookies del usuario. Puede haber situaciones donde estará OK halar valores para afectar el rendereo, pero la mayoría del tiempo usted usará las cookies en el controlador, no en la vista.

10.1.6.5 flash

El flash ha aparecido en ejemplos de código más grandes en todo el libro hasta el momento cada vez que desea enviar al usuario un mensaje desde la capa del controlador, pero sólo por la duración de la siguiente solicitud.

def create
  if user.try(:authorize, params[:user][:password])
    flash[:notice] = "Welcome, #{user.first_name}!"
    redirect_to home_url
  else
    flash[:alert] = "Login invalid"
    redirect_to :new
  end
end

Es una práctica común en Rails usar flash[:notice] ara contener mensajes de noticias benignas y flash[:alert] para la comunicación de naturaleza más seria.

Nota: Es también común setear noticias flash y mensajes de alert sobre los redireccionamientos que Rails le permite setear en el método redirect_to como parámetros opcionales.

def create
  if user.try(:authorize, params[:user][:password])
    redirect_to home_url, notice: "Welcome, #{user.first_name}!"
  else
    redirect_to home_url, alert: "Bad login"
  end
end

Accessors especiales para noticias y alertas son incluidos como métodos helper en el objeto flash mismo, ya que su uso es muy común.

def create
  if user.try(:authorize, params[:user][:password])
    flash.notice = "Welcome, #{user.first_name}!"
    redirect_to home_url
  else
    flash.alert = "Login invalid"
    redirect_to action: "new"
  end
end

###10.1.7 Desplegando mensajes flash

Personalmente, me gusta condicionar tanto la salida de los mensajes notice como de los mensajes alert en un elemento div, en la cima de mi layout, y uso CSS para definir su estilo, como muestro en el Listado 10.3:

Listado 10.3 Ubicación estandarizada de noticias y errores flash en application.html.haml

%html
  ...
  %body
    - if flash.notice
      .notice= flash.notice
    - if flash.alert
      .notice.alert= flash.alert
    = yield

El CSS para .notice define la mayoría del estilo para el elemento, y .alert sobre escribe sólo el aspecto que es diferente para las alertas.

###10.1.8 flash.now

Algunas veces usted desea darle un mensaje flash al usuario pero sólo por el requerimiento actual. De hecho, un error de principiante común es setear una noticia flash y no redireccionar, de este modo mostramos incorrectamente un mensaje en el requerimiento siguiente.

Es posible hacer que flash coopere con un render usando el método flash.now.

class ReportController < ActiveRecord::Base
  def create
    if report.save
      flash.notice = "#{report.title} has been created."
      redirect_to report_path(report)
    else
      flash.now.alert = "#{@post.title} could not be created."
      render :new
    end
  end
end

El objeto flash.now también tiene accessors notice y alert, como su contraparte tradicional.

10.1.8.1 logger

Usted tiene algo que grabar para la posteridad en el logs mientras usted está rendereando la vista? Use el método logger para obtener la instancia Logger de la vista -igual que Rails.logger, a menos que usted lo haya cambiado.

10.1.8.2 params

Este es el mismo hash params que está disponible en su controlador, conteniendo los pares llave/valor de su requerimiento. Yo ocasionalmente use un valor desde el hash params directamente en la vista, particularmente cuando estoy tratando con páginas que tema de filtrado u ordenamiento de filas.

%p
  Filter by month:
  = select_tag(:month_filter, options_for_select(@month_options, params[:month_filter]))

Es muy dañino desde la perspectiva de la seguridad, data de parámetros sin filtrar dentro del stream de salida de su template. El Capítulo 15, "seguridad" cubre este tópico en profundidad.

10.1.8.3 request y response

Los objetos HTTP request y response son expuestos a la vista, pero sólo con propósitos de debugg, no puedo imaginar otra razón para usarlos directamente desde su template.

10.1.8.4 session

La variable session es el hash de sesión del usuario. Puede haber situaciones donde estará bien sacar de ahí valores para afectar el rendereado, pero me estremezco al pensar de que usted pueda tratar de setear valores en la sessión desde la capa de vistas. Úselo con cuidado y principalemente para debugging, igual que con request y response.

##10.2 Parciales

Un parcial es un fragmento de código de template. La forma de Rails de usar parciales para factorizar código de vistas dentro de pedazos modulares que pueden ser ensamblados en layouts con la menor repetición posible. En antiguas versiones de Rails, la sintaxis para incluir un parcial dentro de un template comenzaba con render :partial, pero ahora pasar un string a render dentro de su vista puede ser interpretado como que usted desea renderear un parcial. Los nombres de templates parciales deben comenzar con un underscore, lo cual sirve para separarlos visualmente dentro de un directorio de templates de vistas. Sin embargo, usted puede omitir el underscore cuando se refiere a ellos.

%h1 Details
= render 'details'

###10.2.1 Casos de uso simples

El caso de uso más simple de un parcial es simplemente extraer una porción de código template. Algunos desarrolladores dividen sus templates en partes lógicas al usar la extracción de parciales.Algunas veces es más simple de entender una estructura de una pantalla si las partes significantes son factorizadas fuera de ellas. Por ejemplo, el Listado 10.4 es una pantalla simple de registro de usuario que tiene sus partes factorizadas en parciales.

Listado 10.4 Formulario de registro de usuario simple con parciales

%h1 User Registration
= error_messages_for :user
= form_for :user, url: user_path do
  .registration
    .details.demographic
      = render 'details'
      = render 'demographics'
    .location
      = render 0location'
    .opt_in
      = render 'opt_in'
    .terms
      = render 'terms'
  %p= submit_tag 'Register'

Mientras estamos en ello, dejeme abrirle uno de esos parciales. Para consevar espacio, miraremos uno de los más pequeños, el parcial que contiene los check-boxes opt-in de esta aplicación particular. La fuente esta en el Listado 10.5; note que el nombre comienza con un underscore.

Listado 10.5 El parcial Opt-in en el archivo app/views/users/_opt_in.html.haml

%fieldset#opt_in
  %legend Spam Opt In
  %p
    = check_box :user, :send_event_updates
    Send me updates about events!
    %br
    = check_box :user, :send_site_updates
    Notify me about new services

Personalmente, me gustan los parciales contenidos enteramente en un contenedor etiquetado semánticamente significativo. En el caso del parcial en el Listado 10.5, ambos controles check box están contenidos dentro de un único elemento fieldset, al cual le he dado un atributo id. Siguiendo la regla, más como una guía aislada que cualquier otra cosa, me ayuda a identificar mentalmente a identificar cómo los contenidos de este parcial van a encajar dentro del template padre. Si hemos lideado con otras etiquetas, quizá fuera de un formulario, puedo elegir envolver el markup del parcial dentro de un contenedor div bien identificado en lugar de un fieldset.

Porque no incluir una etiqueta td dentro del template parcial? Es cosa de estilo - a mí me gusta poder ver el esqueleto de etiquetas completo en una pieza. En este caso, el esqueleto es la estructura de la tabla que usted ve en el listado 10.4. Si porciones de la tabla fueran insertadas en templates parciales, complicaría el layout de la página. Tengo que admitir que esta es una de esas áreas donde el estilo y preferencias personales debe tener precedencia, y yo sólo puedo aconsejarle lo que ha funcionado para mi, personalmente.

###10.2.2 Reutilización de parciales

Ya que el formulario de registro esta púlcramente factorizado en sus partes componentes, es fácil crear un formulario de edición simple usando algunos de sus parciales, como en el Listado 10.6.

Listado 10.6 Formulario de edición de usuario simple reutilizando algunos de los mismos parciales

%h1 Edit User
= form_for :user, url: user_path(@user), method: :put do
  .settings
    .details
      = render 'details'
    .demographic
      = render 'demographics'
    .location
      = render 0location'
  .opt_in
    = render 'opt_in'
  %p= submit_tag 'Save Settings'

Si usted compara los Listados 10.4 y 10.6, notará que la estructura de la tabla cambió un poco en el formulario de edición, y tiene menos contenido que el formulario de registro. Quizá la "location" es manejada en mayor detalle en otra pantalla, y ciertamente usted no necesita aceptar los términos cada vez que cambia su seteo.

###10.2.3 Parciales compartidos

Hasta ahora hemos considerado el uso de parciales que residen en el mismo directorio que sus templates padres. Sin ambargo, usted puede fácilmete referirse a paciales que están en otros directorios sólo prefijando el nombre del directorio. Usted aún debe obviar el underscore, que siempre se ha sentido un poco raro.

Agreguemos un parcial captcha abajo del formulario de registro del LIstado 10.4 para ayudarnos a prevenir que los spammers invadan nuestra aplicación web:

...
  .terms
    = render 'terms'
  .captcha
    = render 'shared/captcha'
%p= submit_tag ?Register' 

Ya que el parcial captcha es usado en diferentes partes de la aplicación, hace sentido que resida en una carpeta shared en lugar de un carpeta de una vista particular. Sin embargo debe tener un poco de cuidado cuando mueva código de un template existente a un parcial compartido, Es muy posible que inadvertidamente separe un parcial que depende implícitamente de donde es rendereado.

Por ejemplo, tome el caso del miembro de la lista de correos Rails-talk con un parcial molesto definido en login/_login.html.haml:

= form_tag do
  %fieldset
    %label
      Username:
      = text_field_tag :username, params[:username]
    %br
    %label
      Password
      = password_field_tag :password, params[:password]
    %br
    = submit_tag "Login"

El envío del formulario login trabaja cuando él rendereo su parcial como parte del login acción login del controlador ("la página login") pero no cuando fue incluido como parte de la vista para cualquier otra sección de su website. El problema es que form_tag (cubierto en el próximo capítulo) normalmente toma un parámetro de acción opcional contándole donde postear su información. Si usted deja fuera la opción, el formulario posteará de vuelta a su URL actual, lo cual puede variar para parciales compartidos, dependiendo de donde sea usado el formulario.

###10.2.4 Pasando variables a un parcial

Los parciales heredan el método expuesto a sus templates padres implícitamente. Por esto es que los helpers de formulario usados en los parciales de los listados 10.4 y 10.6 funcionan: Ellos confían implícitamente que un método user esta en scope. Me parece bien usar este compartir implícito en algunos casos, particularmente cuando los parciales están herméticamente unidos a sus templates padres. Esto puede ser especialmente verdadero en casos donde la única razón para romper en un parcial es en primer lugar reducir el tamaño y complejidad de un template particularmente largo.

Sin embargo, una vez que usted adquiere la práctica de romper en templates parciales para su reutilización, dependiendo del contexto implícito se hace mucho más arriesgado. Esta es la razón por la que Rails soporta el paso de variables de alcance local a los templates parciales, como en el siguiente fragmento:

= render 'shared/address', form: form

Los valores del hash opcional son convertidos a variables de alcance local (sin signo @) en el parcial. El Listado 10.7 es una variación sobre el template de registro. Esta vez estamos usando la versión de form_for que produce un parámetro bloque representando el formulario a sus métodos helpers de formulario. Pasaremos el parámetro form también.

%h1 User Registration
= form_for :user, url: users_path do |form|
  .registration
    .details.address.demographic
      = render 'details', form: form
      = render 'shared/address', form: form
  %p= form.submit 'Register'

Y finalmente, en el Listado 10.8 tenemos el formulario de address compartido.

Listado 10.8 Un parcial Address simple compartido usando variable local

%fieldset.address
  %legend.Address
  %p
    %label Street
    %br
    = form.text_area :street, rows: 2, cols: 40
  %p
    %label City
    =form.text_field :city
  %p
    %label State
    %br
    = form.text_field :state, size: 2
  %p
    %label Zip
    %br
    = form.text_field :zip, size: 15

Los métodos helper form, los cuales son cubiertos en el Capítulo 11, "Todo acerca de los Helpers" tienen una variación en la cual son llamados sobre la variable form producida por el método form_for. Esto es exactamente lo qeu hemos pasado a estos parciales.

10.2.4.1 El hash local_assigns

Si usted necesita chequear la presencia de cierta variable local en un parcial, usted necesita hacerlo chequeando el hash local_assigns que es parte de todo template. Usar defined? variable no funciona debido a las limitaciones del sistema de rendereado.

- if local_assigns.has_key? :special
  = special

###10.2.5 Rendereando un objeto

El método render también provee una sintaxis abreviada pra renderear un objeto dentro de un parcial, lo cual depende estrictamente de la convención de nombres de Rails.

render entry

El parcial correspondiente al último fragmento de código es nombrado _entry.html.haml y toma una variable local llamada entry. Esto es equivalente a lo siguiente:

= render partial: 'entry', object: entry

Para setear el nombre de una variable local diferente a la del nombre del parcial, uno puede usar la hash locals como vimos antes en el capítulo o especificar el nombre deseado a través de la opción :as.

= render partial: 'entry', object: some_entry, as: :item

###10.2.6 Rendereando colecciones

Uno de los mejores usos de los parciales es renderear colecciones. Una vez que usted tenga el habito de renderear colecciones con parciales, usted no deseará volver a fealdad de saturar sus templates con loops for y each. Cuando el método render toma un Enumerable como su primer argumento, asume que usted desea renderear una colección de parciales.

render entries

Es simple y muy dependiente de la convención de nombres. El objeto que es rendereado es expuesto al template parcial como una variable local llamada exáctamente como el template parcial mismo. Sucesivamente, el template debe ser nombrado de acuerdo a la clase del objeto que está siendo rendereado.

El parcial correspondiente al último fragmento de código es llamado _entry.html.haml y obtiene la variable local llamada entry.

= div_for(entry) do
  = entry.description
  #(distance_of_time_in_words_to_now entry.created_at) ago

Si la colección pasada dentro del método render está vacía, retorna nil. Usando este conocimiento, usted puede escribir código como el siguiente para proveer contenido de vuelta:

= render(entries) ||  "No entries exist"

Ya que el template parcial usado está basado en la clase de cada ítem, usted puede fácilmente renderear una colección heterogénea de objetos. Esta técnica es particularmente útil en conjunción con colecciones de subclases STI.

Si usted desea sobre escribir este comportamiento, entonces vuelva a la antigua sintaxis de parciales y especifique las opciones :partial y collection explícitamente, como sigue:

partial: 'entry', collection: @entries

**10.2.6.1 la variable partial_counter

Hay otro conjunto de variable para parciales de rendereo de colecciones al que no prestan mucha atención. Es una variable contador indexado en cero que da seguimiento al número de veces que un parcial ha sido rendereado. Es útil para renderear listas numeradas de cosas. El nombre de la variable es el nombre del parcial más _counter.

= div_for(entry) do
  "#{entry_counter}:#{entry.description}
  #{distance_of_time_in_words_to_now entry.created_at} ago"

10.2.6.2 Compartiendo parciales de colecciones

Si usted busca usar el mismo parcial que usted usa con una colección, pero con un único objeto entry, usted tiene que pasar esa instancia única vía el hash locals descrito en la sección precedente, así:

render 'entry', entry: some_entry

###10.2.7 Logging

Si usted hecha una mirada a su log de desarrollo, notará que muestra que parciales ha rendreado y cuanto tiempo le tomó.

Rendering template within layouts/application
Rendering listings/index
Rendered listings/_listing 0.6ms)
Rendered listings/_listing 0.3ms)
Rendered listings/_listing 0.2ms)
Rendered listings/_listing 0.2ms)
Rendered listings/_listing 0.2ms)
Rendered layouts/_login 2.4ms)
Rendered layouts/_header 3.3ms)
Rendered layouts/_footer 0.1ms)
⚠️ **GitHub.com Fallback** ⚠️