El refactor que hice aplica para todo lo que tenga que ver con un comportamiento como sigue:
- Crear alguna entidad a través de un modal.
- Al crearlo, agregar la actividad creada a algún div de la vista.
- Todo esto, a través de ajax (sin que se recargue la página).
Hay varias cosas que tienen ese comportamiento (agregar usuarios, agregar tareas, etc), y para que sea automático hay que hacer lo siguiente:
-
El modal y el form deben tener un ID muy parecido. Deben terminar en -modal y en -form respectivamente. Por ejemplo, si mi modal tiene id igual a add-user-modal, entonces el id del form debe ser add-user-form.
-
El form debe tener un atributo data-target cuyo valor es el selector de un div. La idea es que al enviar el formulario, el servidor responda con un pedazo de html, el cual será colocado en el div especificado por este atributo. Por ejemplo, si pongo 'data-selector' => '#user_table', al enviar ese formulario, el servidor responde con HTML, y mi refactor tomará el div con id user_table y agregará al final este HTML.
-
El form debe tener remote: true, esto es para que se envíe por ajax y por ende, el browser no recargue la página al "Enviar".
-
Al interior del form, debe haber un div con clase form-error, por ejemplo en _app/views/projects/add_user_form
= form_for :assignment, url: add_user_project_path, :html => { :class => 'form-horizontal', id: 'add-user-form', 'data-selector' => '#user_table' }, remote: true do |f|
.form-error
.form-group
= f.label :user, :class => 'col-sm-2 control-label'
.col-sm-10
= f.hidden_field :user_id, class: 'form-control', data: { select: true, url: add_user_list_project_path }
.form-group
= f.label :rol, :class => 'col-sm-2 control-label'
.col-sm-10
= f.collection_select :role_id, @roles, :id, :name, {}, class: 'form-control'
.form-group
.col-sm-offset-2.col-sm-10
= f.submit 'Otorgar cargo', :class => 'btn btn-primary'
%a.btn.btn-default{'data-dismiss' => 'modal'} Cancelar
La idea es que si hay un error al enviar el formulario, se imprima en esa cajita.
- Ahora en el servidor hay que editar el método que procesa el formulario. Más o menos es la siguiente idea:
# En app/controllers/projects_controller.rb
def add_user
assignment = @project.assignments.create(assignment_params) # esto es un .new + asignarle al assignment el proyecto + .save
if assignment.valid?
render partial: true, locals: { assignment: assignment }
else
render partial: true, locals: { assignment: assignment }, :status => 422
end
end
El status 422, significa "entidad improcesable", osea, que no se pudo crear. Esto es para decirle al código que hice que hubo un error, sin esto, no funciona mostrar el error en el modal.
La idea es que si hubo un error, agregar el status 422.
(Los partial son vistas pero cuyo nombre parte con _)
# En app/views/projects/_add_user.html.haml
- if assignment.valid?
%tr
%td= assignment.user.full_name
%td
- if assignment.admin?
= assignment.name
- else
= form_for(assignment, html: {class: 'js-assignment-update-role'}, remote: true) do |f|
.form-group
= f.collection_select :role_id, Role.all_without_admin, :id, :name, {}, class: 'form-control'
%td
-if can?(:update, Assignment) && current_user != assignment.user
= link_to 'Eliminar', assignment_path(assignment), method: :delete, data: { confirm: '¿Estas seguro de eliminar?', remote: true, type: 'json' }, class: 'btn btn-danger js-assignment-delete'
- else
= bootstrap_model_errors(assignment)
Lo que importa ver de aquí es que devolvemos un "tr" (una fila) que será colocada en la tabla, osea, el servidor devuelve lo que tiene que ir en la tabla, y mi refactor lo coloca en el elemento con id que le pasamos en el data-selector
- La tabla de usuarios que se está modificando está en app/views/ṕrojects/show.html.haml (al final del archivo)
#tab3.tab-pane
%table.table#user_table
%thead
%th Usuario
%th Cargo
%th Acción
%tbody
[email protected] do |assignment|
= render partial: 'add_user', locals: { assignment: assignment }
%button.btn.btn-primary#add_user{ 'data-toggle' => 'modal', 'data-target' => '#add-user-modal' } Agregar usuario a proyecto
Estoy imprimiendo el mismo partial que devuelve el método add_user del project, así si hay que modicar la tabla lo hago desde un mismo archivo, y no hay duplicación de código. Lo de locals es porque esa es la forma de pasarle variables a los partials, y no se usa el @ antes de ellas.
En resumen:
- Respetar los ids del modal y form: *-modal, *-form.
- Colocar en el form el data-selector, que tenga valor igual al #id, con id de la cajita donde quiero poner el html de lo que me devuelva el servidor al enviar el form.
- Colocar dentro del form el .form-error
- En el controlador, procesar el formulario y crear lo que tenga que crear. Si hay error, poner lo del status: 422.
- En la vista asociada al método que procesa el formulario (partial), si es válido lo que creé, imprimir el html dependiendo de lo que quiero poner en la cajita a actualizar, y si no, poner SIEMPRE = bootstrap_model_errors(entidad) que imprimirá el html con errores de bootstraps y bonito.
graxias
chao face