#185 Formtastic Part 2
- Download:
- source codeProject Files in Zip (111 KB)
- mp4Full Size H.264 Video (15.3 MB)
- m4vSmaller H.264 Video (10 MB)
- webmFull Size VP8 Video (27.8 MB)
- ogvFull Size Theora Video (20.8 MB)
En el episodio anterior introdujimos Formtastic, una excelente gema para producir vistas con muy poco código. Con él creamos una aplicación básica para una clínica veterinaria que tenía formularios para agregar y editar animales y categorías de animales. En este episodio usaremos algunas funciones más avanzadas de Formtastic para extender nuestra aplicación.
Al final del último episodio, teníamos un formulario que podíamos utilizar para crear y actualizar los detalles de un animal. En este episodio modificaremos el formulario para agregarle algunas características más.
Manejando Relaciones Many-to-Many
Un animal puede llegar a la clínica veterinaria con un varios problemas, por lo que la primer modificación que vamos a realizar en nuestra aplicación es agregar un modelo Problem
. Este modelo tendrá una relación many-to-many con Animal
. En el episodio previo, vimos lo bien que Formtastic maneja las relaciones one-to-many en los formularios cuando lo utilizamos para crear un dropdown de la categoría. No es necesario decir que puede trabajar con relaciones many-to-many de igual forma.
Comenzaremos por crear el scaffolding del modelo Problem
. Como en el episodio anterior, utilizaremos nifty generators de Ryan Bates para crear el scaffold de una forma más simple.
script/generate nifty_scaffold problem name:string
Como estamos creando una relación many-to-many necesitaremos un modelo de join. Crearemos uno llamado Symptom
que referenciará a ambos, Animal
y Problem
.
script/generate nifty_scaffold symptom animal_id:integer problem_id:integer --skip-controller
No hay necesidad de manipular los síntomas directamente desde la interfaz web, por lo que utilizamos la opción --skip-controller
para evitar crear el controlador.
Para completar este paso, migraremos nuestra base de datos para crear las nuevas tablas.
rake db:migrate
Luego, debemos configurar la asociación entre los modelos Problem
, Symptom
y Animal
. Un Problem
tiene muchos Symptoms
y Animals
:
class Problem < ActiveRecord::Base attr_accessible :name has_many :symptoms has_many :animals, :through => :symptoms end
Un Symptom
pertenece a un Problem
y a un Animal
:
class Symptom < ActiveRecord::Base attr_accessible :animal_id, :problem_id belongs_to :animal belongs_to :problem end
Finalmente un Animal
tiene muchos Symptoms
y Problems
:
class Animal < ActiveRecord::Base attr_accessible :name, :category_id, :born_on, :female, :problem_ids belongs_to :category has_many :symptoms has_many :problems, :through => :symptoms end
Hay un cambio más que debemos realizar a nuestro modelo Animal
. Como utilizaremos attr_accessible
para controlar que campos pueden ser actualizados por asignamiento masivo, necesitamos agregar problem_ids
a la lista de campos accesibles de forma de poder asignar múltiples problemas a un animal de forma masiva y permitir actualizaciones a través de la interfaz de usuario.
Ahora que modificamos los modelos podemos actualizar el formulario para que los problemas puedan ser asignado a los animales. Solo necesitamos agregar <%= f.input :problems %>
al formulario de animal para mostrar los problemas como un select múltiple.
<% 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, :label => "Gender", :collection => [["Male", false], ["Female", true]] %> <%= f.input :problems %> <% end %> <%= f.buttons %> <% end %>
Si recargamos la página ahora, veremos la lista de problemas en el formulario. (Agregamos algunos problemas a la base de datos de forma de tener algo que mostrar.) Si seleccionamos un par de problemas y salvamos nuestro animal veremos que están seleccionados al volver a editar el animal.
Nos gustaría mostrar los problemas como una lista de checkboxes en lugar de un select múltiple. La última vez utilizamos la opcion :as de Formtastic para cambiar checkboxes a botones de radio y podemos realizar el mismo cambio aquí para mostrar la lista como checkboxes.
<%= f.input :problems, :as => :checkboxes %>
Otra recarga de la página y los problemas son mostrados como checkboxes, con los ítems previamente seleccionados en el select múltiple chequeados.
Trabajando Con Campos Requeridos
Cada etiqueta de campo tiene un asterisco a su derecha para indicar que es requerido. Formtastic hace que todos los campos sean requeridos por defecto. Podemos sobreescribir este comportamiento para un campo específico utilizando la opción :required
.
<%= f.input :problems, :as => :check_boxes, :required => false %>
Controlar esto campo-por-campo puede convertirse rápidamente en una molestia; sería mucho más fácil si podemos utilizar las validaciones del modelo para controlar que campos son requeridos. Formtastic soporta este comportamiento, pero antes debemos instalar un plugin llamado validation_reflection para poder utilizarlo.
Podemos instalar el plugin en nuestra aplicación desde GitHub.
script/plugin install git://github.com/redinger/validation_reflection.git
Una vez que validation_reflection está instalado, necesitamos reiniciar nuestro servidor así nuestro plugin es reconocido. Si recargamos la página veremos que los asteriscos se han ido. Esto es porque ninguno de los campos del modelo Animal tiene validaciones.
Podemos ahora agregar validaciones a los atributos name
y born_on
para que sear requeridos…
class Animal < ActiveRecord::Base attr_accessible :name, :category_id, :born_on, :female, :problem_ids belongs_to :category has_many :symptoms has_many :problems, :through => :symptoms validates_presence_of :name, :born_on end
…y si recargamos el formulario nuevamente, los asteriscos aparecerán nuevamente en las etiquetas de esos campos.
Como Maneja Formtastic Los Mensajes De Error
Formtastic muestra los mensajes de error de un formulario junto a cada campo. Si quitamos el nombre de nuestro animal y tratamos de actualizar, se mostrará el mensaje de error por defecto.
Podemos cambiar el comportamiento si lo creemos necesario alterando la configuración de Formtastic
Lo mejor es colocar los detalles de configuración en un archivo en el directorio /config/initializers
. Llamaremos al archivo formtastic_config.rb
. La página GitHub de Formtastic tiene los detalles de lo que se puede poner dentro del archivo de configuración e incluso hay un archivo de prueba que podemos consultar. Una de las opciones de configuración listadas aquí es inline_errors
, que es la que debemos cambiar para indicar donde mostrar los errores del formulario. Para ocultar los errores podemos setear inline_errors
a :none
en el archivo de configuración.
Formtastic::SemanticFormBuilder.inline_errors = :none
Si tratamos de enviar el formulario inválido nuevamente no nos mostrará errores. Si queremos desplegar los errores como una lista en el tope del formulario podemos utilizar el método error_messages
para mostrar los errores en el estilo “clásico” de Rails.
<% semantic_form_for @animal do |f| %> <%= f.error_messages %> <% f.inputs do %> <!-- rest of form -->
Los errores son desplegados ahora en el tope del formulario.
Hints
Hay una opción de campos de Formtastic que aún no hemos mostrado: :hint
. Como su nombre sugiere, :hint
muestra un mensaje de hint junto al campo. Para agregar un hint al campo de nombre, solamente necesitamos agregar el mensaje apropiado.
<%= f.input :name, :hint => "Enter the owner’s name if none is provided." %>
Cuando recargamos la página el mensaje de hint es mostrado debajo del campo del formulario.
Si queremos darle estilo al mensaje de hint o a a cualquier otra parte de nuestro formulario, lo podemos hacer modificando el archivo formtastic_changes.css
que Formtastic generó en el pasado episodio cuando ejecutamos
script/generate formtastic_stylesheets
El archivo esta pre-cargado con una sección de comentarios, la cuál para nuestra suerte, incluye un ejemplo de como alterar el estilo del texto del hint. Si queremos que el tamaño del texto del hint sea de 11px y en formato itálica, podemos hacerlo utilizando el siguiente CSS:
form.formtastic fieldset ol li p.inline-hints { font-style: italic; font-size: 11px; }
Recargamos el formulario nuevamente y el texto del hint habrá cambiado.
Si queremos realizar más cambios a la apariencia del formulario, lo mejor es mirar el archivo formtastic.css
para ver como están definidos los estilos por defecto. Podemos utilizar selectores similares en formtastic_changes.css
para sobre-escribir los originales.
Eso es todo por este episodio. Es de esperar que te ha dado suficiente información acerca de Formtastic para persuadirte a que lo pruebes en tus propias aplicaciones. Hay una serie de características que no hemos logrado cubrir en el curso de estos dos episodios. La documentación de Formtastic cubre todas sus características y vale la pena utilizarla para encontrar más información, incluido el soporte de internacionalización