En ocasiones, tenemos modelos asociados que necesitamos manipular en un único formulario en lugar de tener un formulario por cada uno de ellos y en este tutorial les mostrare como crear estos formularios anidados (nested forms).

Un formulario anidado nos permite generar una mejor experiencia de usuario al trabajar con modelos relacionados, ya que de esta manera no se tendrá que estar cambiando a las vistas de cada modelo para hacer cambios.

Para mostrar como trabajar con formularios anidados crearemos un proyecto para listar Bancos y sus sucursales. Un banco se podrá editar en un formulario que incluirá todas sus sucursales.

Hora de codear

Paso 1: Crear Proyecto

Paso 2: Crear los scaffolds

Vamos a necesitar los siguientes dos scaffolds para nuestro ejemplo:

La opción :references crea un campo que hace referencia al modelo, en este caso bank.

 Revisemos el schema.

Paso 3: Asociando los modelos y creando las validaciones

Ahora vamos a crear la asociación entre los modelos, que en este caso es una relación de ‘uno a muchos’, es decir, un banco puede tener muchas sucursales pero una sucursal solo puede pertenecer a un banco. También validaremos los campos que son obligatorios para nuestros modelos.

Tip: se puede añadir un método llamado to_s y pedirle que imprima la columna que queremos cuando llamamos al objeto y así no tener que especificarlo cada vez que lo usamos. Ej: ‘instancia’ v/s ‘instancia.columna’

 

También usaremos el archivo seeds para crear datos para probar la aplicación.

 

Ahora ejecutamos nuestro seed, e iniciamos el servidor:

 

Paso 4: Mostrando las sucursales en el detalle del banco

Queremos que al entrar al detalle de un banco nos muestre todas las sucursales asociadas a este, por lo que tenemos que modificar en archivo /app/views/banks/show.html.erb y agregar lo que esta entre la linea 8 y 18:

 

Paso 5: Modificando el formulario del modelo bank

En el siguiente paso modificaremos el formulario del modelo bank para que podamos agregar sucursales cuando entramos a editar el banco, para esto usaremos el Helper fields_for.

Ahora si entramos a editar el banco tendremos un campo para añadir una sucursal, pero no esta mostrando las sucursales que ya existen, para eso vamos a modificar nuestro modelo bank y añadiremos lo siguiente:

Ahora si recargamos la pagina veremos que se mostraran las sucursales asociadas al banco seleccionado.

Paso 6: Editando una sucursal

Si ahora tratamos de editar alguna de las sucursales nos daremos cuenta que el cambio no se aplica, y si revisamos la consola nos encontraremos con el problema:  

Unpermitted parameter: bank_subsidiaries_attributes

Lo que tenemos que hacer ahora es ir al controlador de bank y agregamos bank_subsidiaries_attributes  a los strong parametersEsta es una medida de seguridad de Rails 4.

Si probamos nuevamente editar una sucursal ahora si se aplicaran los cambios!

 

Paso 7: Agregar una nueva sucursal

En estos momentos al editar un banco se listan todas las sucursales asociadas a éste pero no tenemos como añadir una nueva sucursal. Esto lo arreglaremos fácilmente haciendo una pequeña modificación en /app/controllers/banks_controller.rb en el método edit:

Si ahora vamos a editar un banco, ademas de tener listadas las sucursales, tendremos un campo vacío para añadir una nueva. Pero si hacemos una prueba tendremos un error, ya que en nuestro modelo bank_subsidiary dijimos que no podemos tener el campo address vacío (validates :address, presence: true), esta validación no la podemos eliminar por lo que tendremos que hacer lo siguiente:

Lo que hicimos fue, a nuestro accept_nested_attributes_for, agregar un reject_if que comprueba si el atributo anidado esta en blanco, y si lo esta no toma en cuenta el accept_nested_attributes_for y en via el formulario sin ellos.

Ahora seria bueno que al añadir un nuevo banco tengamos la posibilidad de añadir una sucursal en el mismo formulario. Para esto hacemos un pequeño cambio en /app/controllers/banks_controller.rb en el método new:

 

Paso 8: Borrar una sucursal en el formulario del banco

Ahora somos capaces de editar y crear sucursales en el formulario del banco. Pero no tenemos ninguna manera de poder eliminar una en este formulario. Para poder hacer esto necesitaremos agregar allow_destroy: true a nuestro accepts_nested_attributes_for:

También tenemos que modificar nuestro formulario para añadir una opción de borrar, esto lo haremos agregando un campo check_box y le pasamos como atributo  :_destroy (este se tiene que llamar así).

Y obviamente tenemos que agregar este atributo en los strong parameter del controlador:

Ahora si podemos agregar, editar y eliminar sucursales desde el mismo formulario del banco!!!

Y ya hemos terminado con nuestro tutorial, a continuación les dejo unos links para profundizar en el tema.

  • Link al repositorio de este tutorial en github: Nested Forms
  • Mas sobre Nested Forms en este link
  • Si quieres aprender mas sobre Nested Attributes mira este link
Share Button

Diseñador de profesión, amante del diseño del desarrollo web y la creación de aplicaciones con Ruby on Rails.

Fundador de La Legion Studio y profesor en DesafioLatam.
Apple Expert y por sobre todo Dog Lover.