1 ¿Qué es Action View?
En Rails, las solicitudes web son manejadas por Action Controller y Action View. Normalmente, Action Controller se encarga de comunicarse con la base de datos y realizar acciones CRUD cuando sea necesario. Luego, Action View es responsable de compilar la respuesta.
Las plantillas de Action View se escriben utilizando Ruby incrustado en etiquetas mezcladas con HTML. Para evitar sobrecargar las plantillas con código repetitivo, varias clases auxiliares proporcionan comportamientos comunes para formularios, fechas y cadenas. También es fácil agregar nuevos ayudantes a tu aplicación a medida que evoluciona.
NOTA: Algunas características de Action View están vinculadas a Active Record, pero eso no significa que Action View dependa de Active Record. Action View es un paquete independiente que se puede usar con cualquier tipo de bibliotecas de Ruby.
2 Uso de Action View con Rails
Para cada controlador, hay un directorio asociado en el directorio app/views
que contiene los archivos de plantilla que conforman las vistas asociadas con ese controlador. Estos archivos se utilizan para mostrar la vista que resulta de cada acción del controlador.
Veamos qué hace Rails de forma predeterminada al crear un nuevo recurso utilizando el generador de andamios:
$ bin/rails generate scaffold article
[...]
invoke scaffold_controller
create app/controllers/articles_controller.rb
invoke erb
create app/views/articles
create app/views/articles/index.html.erb
create app/views/articles/edit.html.erb
create app/views/articles/show.html.erb
create app/views/articles/new.html.erb
create app/views/articles/_form.html.erb
[...]
Hay una convención de nomenclatura para las vistas en Rails. Normalmente, las vistas comparten su nombre con la acción del controlador asociada, como se puede ver arriba.
Por ejemplo, la acción del controlador index
del archivo articles_controller.rb
utilizará el archivo de vista index.html.erb
en el directorio app/views/articles
.
El HTML completo devuelto al cliente está compuesto por una combinación de este archivo ERB, una plantilla de diseño que lo envuelve y todos los parciales a los que la vista puede hacer referencia. En esta guía, encontrarás documentación más detallada sobre cada uno de estos tres componentes.
Como se mencionó, la salida HTML final es una composición de tres elementos de Rails: Plantillas
, Parciales
y Diseños
.
A continuación se muestra una breve descripción de cada uno de ellos.
3 Plantillas
Las plantillas de Action View se pueden escribir de varias formas. Si el archivo de plantilla tiene una extensión .erb
, entonces se utiliza una mezcla de ERB (Ruby incrustado) y HTML. Si el archivo de plantilla tiene una extensión .builder
, se utiliza la biblioteca Builder::XmlMarkup
.
Rails admite múltiples sistemas de plantillas y utiliza una extensión de archivo para distinguir entre ellos. Por ejemplo, un archivo HTML que utiliza el sistema de plantillas ERB tendrá .html.erb
como extensión de archivo.
3.1 ERB
Dentro de una plantilla ERB, se puede incluir código Ruby utilizando las etiquetas <% %>
y <%= %>
. Las etiquetas <% %>
se utilizan para ejecutar código Ruby que no devuelve nada, como condiciones, bucles o bloques, y las etiquetas <%= %>
se utilizan cuando se desea obtener una salida.
Considera el siguiente bucle para los nombres:
<h1>Nombres de todas las personas</h1>
<% @people.each do |person| %>
Nombre: <%= person.name %><br>
<% end %>
El bucle se configura utilizando etiquetas de incrustación regulares (<% %>
) y el nombre se inserta utilizando etiquetas de incrustación de salida (<%= %>
). Ten en cuenta que esto no es solo una sugerencia de uso: las funciones de salida regulares como print
y puts
no se renderizarán en la vista con las plantillas ERB. Por lo tanto, esto sería incorrecto:
<%# INCORRECTO %>
Hola, Sr. <% puts "Frodo" %>
Para suprimir los espacios en blanco iniciales y finales, puedes usar <%-
-%>
de manera intercambiable con <%
y %>
.
3.2 Builder
Las plantillas de Builder son una alternativa más programática a ERB. Son especialmente útiles para generar contenido XML. Se crea automáticamente un objeto XmlMarkup llamado xml
que está disponible en las plantillas con una extensión .builder
.
Aquí tienes algunos ejemplos básicos:
xml.em("enfatizado")
xml.em { xml.b("énfasis y negrita") }
xml.a("Un enlace", "href" => "https://rubyonrails.org")
xml.target("nombre" => "compilar", "opción" => "rápido")
que produciría:
<em>enfatizado</em>
<em><b>énfasis y negrita</b></em>
<a href="https://rubyonrails.org">Un enlace</a>
<target opción="rápido" nombre="compilar" />
Cualquier método con un bloque se tratará como una etiqueta de marcado XML con marcado anidado en el bloque. Por ejemplo, lo siguiente:
ruby
xml.div {
xml.h1(@person.name)
xml.p(@person.bio)
}
produciría algo como:
<div>
<h1>David Heinemeier Hansson</h1>
<p>Un producto del Diseño Danés durante el Invierno del '79...</p>
</div>
A continuación se muestra un ejemplo completo de RSS que se utiliza en Basecamp:
xml.rss("version" => "2.0", "xmlns:dc" => "http://purl.org/dc/elements/1.1/") do
xml.channel do
xml.title(@feed_title)
xml.link(@url)
xml.description "Basecamp: Ítems recientes"
xml.language "en-us"
xml.ttl "40"
for item in @recent_items
xml.item do
xml.title(item_title(item))
xml.description(item_description(item)) if item_description(item)
xml.pubDate(item_pubDate(item))
xml.guid(@person.firm.account.url + @recent_items.url(item))
xml.link(@person.firm.account.url + @recent_items.url(item))
xml.tag!("dc:creator", item.author_name) if item_has_creator?(item)
end
end
end
end
3.3 Jbuilder
Jbuilder es una gema que es mantenida por el equipo de Rails y está incluida en el Gemfile
predeterminado de Rails. Es similar a Builder pero se utiliza para generar JSON en lugar de XML.
Si no lo tienes, puedes agregar lo siguiente a tu Gemfile
:
gem 'jbuilder'
Un objeto Jbuilder llamado json
se crea automáticamente y está disponible en las plantillas con extensión .jbuilder
.
Aquí tienes un ejemplo básico:
json.name("Alex")
json.email("[email protected]")
produciría:
{
"name": "Alex",
"email": "[email protected]"
}
Consulta la documentación de Jbuilder para obtener más ejemplos e información.
3.4 Caché de plantillas
Por defecto, Rails compilará cada plantilla en un método para renderizarla. En el entorno de desarrollo, cuando modificas una plantilla, Rails verificará la fecha de modificación del archivo y la volverá a compilar.
4 Partials
Las plantillas parciales, generalmente llamadas "partials", son otro recurso para dividir el proceso de renderizado en fragmentos más manejables. Con los partials, puedes extraer fragmentos de código de tus plantillas y reutilizarlos en toda tu aplicación.
4.1 Renderización de partials
Para renderizar un partial como parte de una vista, utilizas el método render
dentro de la vista:
<%= render "menu" %>
Esto renderizará un archivo llamado _menu.html.erb
en ese punto de la vista que se está renderizando. Observa el carácter de guion bajo al principio: los partials se nombran con un guion bajo al principio para distinguirlos de las vistas regulares, aunque se los menciona sin el guion bajo. Esto es válido incluso cuando estás utilizando un partial de otra carpeta:
<%= render "shared/menu" %>
Ese código utilizará el partial de app/views/shared/_menu.html.erb
.
4.2 Uso de partials para simplificar las vistas
Una forma de utilizar los partials es tratarlos como equivalentes a subrutinas; una forma de mover los detalles de una vista para poder comprender mejor lo que está sucediendo. Por ejemplo, podrías tener una vista que se vea así:
<%= render "shared/ad_banner" %>
<h1>Productos</h1>
<p>Aquí tienes algunos de nuestros excelentes productos:</p>
<% @products.each do |product| %>
<%= render partial: "product", locals: { product: product } %>
<% end %>
<%= render "shared/footer" %>
Aquí, los partials _ad_banner.html.erb
y _footer.html.erb
podrían contener contenido que se comparte en muchas páginas de tu aplicación. No necesitas ver los detalles de estas secciones cuando te estás concentrando en una página en particular.
4.3 render
sin las opciones partial
y locals
En el ejemplo anterior, render
toma 2 opciones: partial
y locals
. Pero si estas son las únicas opciones que deseas pasar, puedes omitir el uso de estas opciones. Por ejemplo, en lugar de:
<%= render partial: "product", locals: { product: @product } %>
También puedes hacer:
<%= render "product", product: @product %>
4.4 Las opciones as
y object
De forma predeterminada, ActionView::Partials::PartialRenderer
tiene su objeto en una variable local con el mismo nombre que la plantilla. Entonces, dado:
<%= render partial: "product" %>
dentro del partial _product
obtendremos @product
en la variable local product
, como si hubiéramos escrito:
<%= render partial: "product", locals: { product: @product } %>
La opción object
se puede utilizar para especificar directamente qué objeto se renderiza en el partial; útil cuando el objeto de la plantilla está en otro lugar (por ejemplo, en una variable de instancia diferente o en una variable local).
Por ejemplo, en lugar de:
<%= render partial: "product", locals: { product: @item } %>
haríamos:
<%= render partial: "product", object: @item %>
Con la opción as
, podemos especificar un nombre diferente para dicha variable local. Por ejemplo, si quisiéramos que fuera item
en lugar de product
, haríamos:
<%= render partial: "product", object: @item, as: "item" %>
Esto es equivalente a
erb
<%= render partial: "product", locals: { item: @item } %>
4.5 Renderizando Colecciones
Comúnmente, una plantilla necesitará iterar sobre una colección y renderizar una sub-plantilla para cada uno de los elementos. Este patrón se ha implementado como un único método que acepta un array y renderiza un partial para cada uno de los elementos en el array.
Entonces, este ejemplo para renderizar todos los productos:
<% @products.each do |product| %>
<%= render partial: "product", locals: { product: product } %>
<% end %>
puede ser reescrito en una sola línea:
<%= render partial: "product", collection: @products %>
Cuando un partial es llamado con una colección, las instancias individuales del partial tienen acceso al miembro de la colección que está siendo renderizado a través de una variable llamada como el partial. En este caso, el partial es _product
, y dentro de él, puedes referirte a product
para obtener el miembro de la colección que está siendo renderizado.
Puedes usar una sintaxis abreviada para renderizar colecciones. Suponiendo que @products
es una colección de instancias de Product
, simplemente puedes escribir lo siguiente para obtener el mismo resultado:
<%= render @products %>
Rails determina el nombre del partial a utilizar al mirar el nombre del modelo en la colección, en este caso Product
. De hecho, incluso puedes renderizar una colección compuesta por instancias de diferentes modelos usando esta sintaxis abreviada, y Rails elegirá el partial adecuado para cada miembro de la colección.
4.6 Plantillas de Espaciado
También puedes especificar un segundo partial para ser renderizado entre las instancias del partial principal usando la opción :spacer_template
:
<%= render partial: @products, spacer_template: "product_ruler" %>
Rails renderizará el partial _product_ruler
(sin datos pasados a él) entre cada par de partials _product
.
4.7 Locales Estrictas
Por defecto, las plantillas aceptarán cualquier locals
como argumentos de palabras clave. Para definir qué locals
acepta una plantilla, agrega un comentario mágico locals
:
<%# locals: (message:) -%>
<%= message %>
También se pueden proporcionar valores predeterminados:
<%# locals: (message: "¡Hola, mundo!") -%>
<%= message %>
O las locals
se pueden deshabilitar por completo:
<%# locals: () %>
5 Layouts
Los layouts se pueden utilizar para renderizar una plantilla de vista común alrededor de los resultados de las acciones del controlador de Rails. Típicamente, una aplicación de Rails tendrá un par de layouts en los que se renderizarán las páginas. Por ejemplo, un sitio puede tener un layout para un usuario registrado y otro para el lado de marketing o ventas del sitio. El layout para el usuario registrado puede incluir una navegación de nivel superior que debe estar presente en muchas acciones del controlador. El layout de ventas para una aplicación SaaS puede incluir una navegación de nivel superior para cosas como las páginas "Precios" y "Contáctenos". Se esperaría que cada layout tenga un aspecto y una sensación diferentes. Puedes leer más detalles sobre los layouts en la guía Layouts and Rendering in Rails.
5.1 Layouts Parciales
Los partials pueden tener sus propios layouts aplicados a ellos. Estos layouts son diferentes de los aplicados a una acción del controlador, pero funcionan de manera similar.
Digamos que estamos mostrando un artículo en una página que debe envolverse en un div
para fines de visualización. En primer lugar, crearemos un nuevo Article
:
Article.create(body: '¡Los Layouts Parciales son geniales!')
En la plantilla show
, renderizaremos el partial _article
envuelto en el layout box
:
articles/show.html.erb
<%= render partial: 'article', layout: 'box', locals: { article: @article } %>
El layout box
simplemente envuelve el partial _article
en un div
:
articles/_box.html.erb
<div class='box'>
<%= yield %>
</div>
Ten en cuenta que el layout del partial tiene acceso a la variable local article
que se pasó a la llamada render
. Sin embargo, a diferencia de los layouts de toda la aplicación, los layouts parciales todavía tienen el prefijo de guión bajo.
También puedes renderizar un bloque de código dentro de un layout parcial en lugar de llamar a yield
. Por ejemplo, si no tuviéramos el partial _article
, podríamos hacer esto en su lugar:
articles/show.html.erb
<% render(layout: 'box', locals: { article: @article }) do %>
<div>
<p><%= article.body %></p>
</div>
<% end %>
Suponiendo que usamos el mismo partial _box
de arriba, esto produciría el mismo resultado que el ejemplo anterior.
6 Rutas de Vistas
Cuando se renderiza una respuesta, el controlador necesita resolver dónde se encuentran las diferentes vistas. Por defecto, solo busca dentro del directorio app/views
.
Podemos agregar otras ubicaciones y darles cierta precedencia al resolver rutas utilizando los métodos prepend_view_path
y append_view_path
.
6.1 Prepend View Path
Esto puede ser útil, por ejemplo, cuando queremos poner vistas dentro de un directorio diferente para subdominios.
Podemos hacer esto usando:
prepend_view_path "app/views/#{request.subdomain}"
Entonces Action View buscará primero en este directorio al resolver vistas.
6.2 Append View Path
De manera similar, podemos agregar rutas:
append_view_path "app/views/direct"
Esto agregará app/views/direct
al final de las rutas de búsqueda.
7 Helpers
Rails proporciona muchos métodos auxiliares para usar con Action View. Estos incluyen métodos para:
- Formatear fechas, cadenas y números
- Crear enlaces HTML a imágenes, videos, hojas de estilo, etc...
- Sanitizar contenido
- Crear formularios
- Localizar contenido
Puedes obtener más información sobre los helpers en la Guía de Helpers de Action View y la Guía de Helpers de Formularios de Action View.
8 Vistas Localizadas
Action View tiene la capacidad de renderizar diferentes plantillas dependiendo de la configuración regional actual.
Por ejemplo, supongamos que tienes un ArticlesController
con una acción show
. Por defecto, llamar a esta acción renderizará app/views/articles/show.html.erb
. Pero si estableces I18n.locale = :de
, entonces se renderizará app/views/articles/show.de.html.erb
en su lugar. Si la plantilla localizada no está presente, se utilizará la versión sin decorar. Esto significa que no es necesario proporcionar vistas localizadas para todos los casos, pero se preferirán y utilizarán si están disponibles.
Puedes usar la misma técnica para localizar los archivos de rescate en tu directorio público. Por ejemplo, establecer I18n.locale = :de
y crear public/500.de.html
y public/404.de.html
te permitiría tener páginas de rescate localizadas.
Dado que Rails no restringe los símbolos que utilizas para establecer I18n.locale
, puedes aprovechar este sistema para mostrar contenido diferente dependiendo de lo que desees. Por ejemplo, supongamos que tienes algunos usuarios "expertos" que deberían ver páginas diferentes de los usuarios "normales". Podrías agregar lo siguiente a app/controllers/application_controller.rb
:
before_action :set_expert_locale
def set_expert_locale
I18n.locale = :expert if current_user.expert?
end
Luego podrías crear vistas especiales como app/views/articles/show.expert.html.erb
que solo se mostrarían a los usuarios expertos.
Puedes leer más sobre la API de Internacionalización (I18n) de Rails aquí.
Comentarios
Se te anima a ayudar a mejorar la calidad de esta guía.
Por favor, contribuye si encuentras algún error tipográfico o factual. Para empezar, puedes leer nuestra contribución a la documentación sección.
También puedes encontrar contenido incompleto o desactualizado. Por favor, añade cualquier documentación faltante para main. Asegúrate de revisar Edge Guides primero para verificar si los problemas ya están resueltos o no en la rama principal. Consulta las Directrices de las Guías de Ruby on Rails para el estilo y las convenciones.
Si por alguna razón encuentras algo que corregir pero no puedes solucionarlo tú mismo, por favor abre un problema.
Y por último, cualquier tipo de discusión sobre la documentación de Ruby on Rails es muy bienvenida en el Foro oficial de Ruby on Rails.