homeASCIIcasts

184: Formtastic Parte 1 

(view original Railscast)

Other translations: En Tr

Other formats:

Written by Leandro Bertolami

Si encuentras que escribir el código de las vistas es más que una tarea tediosa, estarás alegre de saber que existe una librería llamada Formtastic que proporciona una manera más concisa para hacerlo. Con ésta, formularios complejos se pueden crear con relativamente poco código como te mostraremos en este episodio.

Creando la aplicación Vet

Antes de comenzar con Formtastic, vale la pena mencionar que existe un paquete de TextMate. El mismo proporciona una serie de útiles fragmentos de código que pueden hacer que la creación de formularios sea aún más fácil.

Para demostrar el funcionamiento de Formtastic, crearemos una nueva aplicación Rails. Esta aplicación llevará el registro de pacientes animales en una clínica veterinaria. Llamaremos a la aplicación vet y la crearemos de forma normal.

rails vet

Formtastic es distribuido como una gema. Podemos incluirla en nuestra aplicación agregando las siguiente línea en el archivo /config/environment.rb. (Si estás utilizando TextMate e instalaste el paquete de Formtastic puedes usar ftgem y <TAB> como un acceso directo).

config.gem 'justinfrench-formtastic', :lib => 'formtastic', :source => 'http://gems.github.com'

Para asegurarnos que la gema está instalada, necesitamos ejecutar

  sudo rake gems:install
  

así estamos listos para comenzar a escribir nuestra aplicación.

Nuestra aplicación utilizará la biblioteca nifty generators de Ryan Bates para facilitar el desarrollo de partes de la misma. Lo primero que usaremos es el generador nifty_layout, el cuál creará un layout y una hoja de estilos

  script/generate nifty_layout
  

Luego generaremos nuestro primer modelo, utilizando el generador nifty_scaffold para crear un controlador y las vistas correspondientes. Pondremos nuestros animales en categorías, así que llamaremos a nuestro modelo Category y le daremos los atributos name y description.

  script/generate nifty_scaffold category name:string description:text
  

Ahora podemos migrar nuestra base de datos.

rake db:migrate

Si corremos nuestra nueva aplicación y navegamos a la página para crear una nueva categoría, veremos el código generado para la vista por el scaffold

The default New Category page.

El código generado por el scaffolding para el formulario anterior es el siguiente:

  <% form_for @category do |f| %>
    <%= f.error_messages %>
    <p>
      <%= f.label :name %><br />
      <%= f.text_field :name %>
    </p>
    <p>
      <%= f.label :description %><br />
      <%= f.text_area :description, :rows => 5 %>
    </p>
    <p><%= f.submit "Submit" %></p>
  <% end %>
  

Esto es código normal para un formulario Rails, comenzando con form_for y definiendo separadamente cada campo del formulario junto a su etiqueta. Finalmente, hay un botón de enviar con el que podremos agregar una nueva categoría.

Formtastic no sobreescribe ninguno de los métodos estándar, por lo que aún podremos utilizarlos en un formulario Formtastic. Si reemplazamos el form_for en el formulario anterior con semantic_form_for de Formtastic, el formulario funcionaría de la misma manera. No tiene mucho sentido hacer eso, sin embargo; la verdadera ventaja aparece cuando utilizamos los métodos de Formtastic. Con ellos, podemos cambiar nuestro formulario para que se vea de la siguiente forma:

  <% semantic_form_for @category do |f| %>
   <%= f.inputs %>
   <%= f.buttons %>
  <% end %>
  

El método inputs es una manera conveniente de generar todos los campos para un modelo, igualmente, el método buttons genera el botón de enviar. Si ahora recargamos el formulario, se ve un poco diferente.

The New Category page using Formtastic code.

Este formulario ahora es mostrado utilizando los métodos de Formtastic. La diferencia más notoria es que mientras el formulario generado a través de scaffold utilizaba tags de párrafos, Formtastic utiliza listas ordenadas y fieldsets para separar los campos de entrada de los botones.

El formulario no se ve particularmente lindo como está, pero podemos arreglarlo aplicando un poco de CSS. Formtastic viene con algunas hojas de estilo existentes que podemos generar para no tener que hacer todo el trabajo nosotros mismos. Si corremos

  script/generate formtastic_stylesheets
  

dos nuevas hojas de estilos serán creadas en el directorio /public/stylesheets de nuestra aplicación y nos permite referenciarlas desde nuestro archivo de layout. En la sección head de nuestro layout ya estamos referenciando una hoja de estilo.

  <head>
    <title><%= h(yield(:title) || "Untitled") %></title>
    <%= stylesheet_link_tag 'application' %>
    <%= yield(:head) %>
  </head>
  

Podemos agregar las dos hojas de estilo de Formtastic aquí para incluirlas en todas las páginas de nuestra aplicación

  <%= stylesheet_link_tag 'application', 'formtastic', 'formtastic_changes' %>
  

El segundo archivo, formtastic_changes, es donde deberíamos realizar cualquier cambio al estilo por defecto provisto por Formtastic. Como ahora tenemos múltiples hojas de estilos, deberíamos utilizar la opción de cache de Rails de forma de combinar todos los archivos en uno solo cuando lo corramos en modo producción (Esto también se aplica a múltiples archivos JavaScript)

  <%= stylesheet_link_tag 'application', 'formtastic', 'formtastic_changes', :cache => 'base' %>
  

Utilizando el cacheo de esta forma significa que menos cantidad de archivos serán pedidos al servidor cuando se carga la página, ya que las tres hojas de estilos serán combinadas en una sola llamada base.css

Si recargamos el formulario ahora, se verá un poco mejor, pero todavía no como se debería ver.

The form's layout isn't quite correct.

Esto es por un par de líneas en la hoja de estilos de Formtastic.

  html[xmlns] form.formtastic fieldset { display: block; }

  html[xmlns] form.formtastic fieldset ol li { display: block; }
  

Los dos selectores CSS anteriores esperan que el comienzo de las páginas, el tag <html>, tenga el atributo xmlns. En el archivo de layout generado por nifty_layout el tag no tiene este atributo, por lo que tendremos que agregarlo para que el formulario se muestre como debería.

  <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
  

Recargamos el formulario ahora y veremos como los campos de texto se alinean como hubiéramos esperado. Hora que el formulario se ve como debería podemos agregar un par de categorías, una para perros y otra para gatos. Las utilizaremos pronto cuando creemos el formulario para animales.

Adding our first category.

Un ejemplo más complejo

Ahora pasaremos al formulario para los animales. Como con las categorías, comenzaremos por generar el scaffold.

  script/generate nifty_scaffold animal name:string category_id:integer born_on:date female:boolean
  

El modelo Animal tendrá los atributos name, born_on y female junto con un category_id así podremos poner cada animal dentro de una Category. Luego de crear el scaffold ejecutaremos la migración de nuestra base de datos nuevamente de forma que la nueva tabla sea creada.

  rake db:migrate
  

El siguiente paso es crear las relaciones entre modelos, así es que un animal pertenece a una categoría…

  class Animal < ActiveRecord::Base
    attr_accessible :name, :category_id, :born_on, :female
    belongs_to :category
  end
  

…y una categoría tiene muchos animales.

  class Category < ActiveRecord::Base
    attr_accessible :name, :description
    has_many :animals
  end
  

El formulario generado por el scaffolding se muestra debajo. Queremos reemplazarlo con un poco de código Formtastic así que lo cambiaremos pronto.

The default New Animal page.

Como en el formulario de categoría, reemplazaremos el código por defecto de form_for por el código de Formtastic semantic_form_for.

  <% semantic_form_for @animal do |f| %>
    <% f.inputs do %>
      <%= f.input :name %>
      <%= f.input :born_on %>
      <%= f.input :category %>
      <%= f.input :female %>
    <% end %>
    <%= f.buttons %>
  <% end %>
  

Esta vez vamos a querer más control sobre los campos de nuestro formulario así que vamos a personalizarlos pronto por lo que hemos pasado un bloque f.inputs y dentro del mismo usamos el método input para definir cada campo. Luego de haber cerrado el bloque, podemos agregar nuestro botón enviar con f.buttons al igual que lo hicimos anteriormente.

Si recargamos el formulario ahora, veremos que los campos son mostrados a través de Formtastic.

The New Animal page with the Formtastic controls on it.

Formtastic ha creado campos de formularios apropiados a los tipos atributos del modelo Animal. Aunque no lo puedes ver aquí, incluso ha inferido que el campo category_id es una asociación y ha cargado el dropdown de categorías con las categorías que agregamos anteriormente.

Hay algunos cambios que queremos hacerle a este formulario. Por defecto, la parte del año de la fecha es cargada únicamente con cinco años hacia cada lado del año actual y precisamos mostrar fechas más atrás que eso. También queremos quitar la opción en blanco del dropdown de category y mostrar el campo female como un par de botones de radio en lugar de un checkbox.

Podemos personalizar campos usando las mismas opciones que pasamos a los helpers de formularios de Rails. Esto significa que podemos pasarle a born_on :start_year y podemos usar el parámetro :include_blank => false en nuestra categoría para quitar la opción en blanco.

  <% semantic_form_for @animal do |f| %>
    <% f.inputs do %>
      <%= f.input :name %>
      <%= f.input :born_on, :start_year => 1900 %>
      <%= f.input :category, :include_blank => false %>
      <%= f.input :female, :as => :radio %>
    <% end %>
    <%= f.buttons %>
  <% end %>
  

Tenemos que tratar el campo female un poco diferente ya que estamos cambiando el tipo del elemento en el formulario. Para especificar un tipo de campo diferente al por defecto, Formtastic proporciona el parámetro :as. Podemos usar :as => :radio para cambiar el tipo a botones de radio

Si miramos nuevamente el formulario, veremos que los cambios que realizamos efectivamente se reflejan en el mismo, con las fechas comenzando desde 1900, la opción en blanco no está en la categoría y el checkbox de female fue reemplazado por dos botones de radio

The gender field is now rendered as radio buttons.

Los botones de radio son una mejora con respecto al checkbox, pero en lugar de “yes” y “no” queremos que la etiqueta del campo sea “Gender” y que los botones de radio sean “Male” y “Female”. ¿Permite Formtastic éste nivel de personalización? Así es. Podemos utilizar las opciones :label y :collection para asignar los valores de la etiqueta y los botones de radio.

  <%= f.input :female, :as => :radio, :label => "Gender", :collection => [["Male", false], ["Female", false]] %>
  

Como su nombre lo indica, la opción :label asigna el nombre de la etiqueta mientras que la opción :collection toma un array de arrays especificando el nombre y valor de cada botón de radio.

El formulario ahora se ve como queremos.

The labels on the radio buttons are changed to the text we want.

Nuestro formulario está ahora completo y podemos utilizarlo para crear cuantos animales queramos.

Llevándolo más lejos

Con Formtastic hemos creado un formulario bastante complejo con relativamente poco código en la vista, utilizando sus opciones de personalización para alterar alguno de los campos a nuestra necesidad. Todavía hay bastante de Formtastic que no hemos cubierto aunque lo haremos en el próximo episodio.