Cómo funciona en la práctica una asociación has_many :through
On enero 3, 2022 by adminCuando empiezas a trabajar con Rails y ActiveRecord, puede ser difícil entender el concepto de las asociaciones has_many :through y, sobre todo, cómo se pueden utilizar en tu aplicación Rails.
«Digamos que tengo un grupo, un miembro, una membresía… ¿cómo utilizo esto en mis modelos, controladores y vistas?»
«Estoy utilizando una relación has_many :through que parece funcionar. Ahora necesito un formulario que pueda renderizar para que los usuarios se unan o abandonen el grupo.»
En primer lugar, deberías estar razonablemente seguro de que una asociación has_many :through es una buena opción para el diseño de tu aplicación. Suponiendo que lo estés, aquí tienes cómo ponerlo en práctica.
Digamos que estás construyendo una app con Usuarios y Grupos, y quieres construir un formulario en el que un determinado usuario pueda unirse o abandonar cualquier grupo. Has elegido asociar tus usuarios y grupos a través de la tabla Membership.
Tus modelos están estructurados así:
class User < ActiveRecord::Base has_many :memberships has_many :groups, through: :membershipsendclass Group < ActiveRecord::Base has_many :memberships has_many :users, through: :membershipsendclass Membership < ActiveRecord::Base belongs_to :user belongs_to :groupend
Siempre me resulta útil, antes de empezar a escribir mis controladores o vistas, pensar en lo que quiero conseguir, y utilizar la consola de Rails para asegurarme de que estoy en el camino correcto. En otras palabras, trato de llegar a un objetivo final, y luego trabajar hacia atrás con la ayuda de la consola de Rails para averiguar mi solución.
Así que, dado que queremos renderizar un formulario que permita a un usuario unirse o abandonar un grupo, deberíamos preguntarnos, «¿qué significa que un usuario se una a un grupo?»
En cuanto a la base de datos, significa esencialmente que la tabla Membership
tendrá una fila con las columnas user_id
y group_id
correspondientes a nuestro usuario y grupo dados. Nuestra tarea entonces es orquestar las cosas de tal manera que cuando el usuario haga clic en ‘enviar’ en su formulario, la tabla Membership
termine con una nueva fila (o filas) con los valores correctos de user_id
y group_id
.
En el formulario/vista que renderizamos para el usuario, necesitamos una forma en la que el usuario pueda seleccionar a qué grupos quiere unirse. Y en el controlador, queremos extraer las opciones que el usuario hizo en el formulario y utilizar esas opciones para crear nuevas filas en la tabla Membership
.
Primero, imagina que tienes un user_id
y un group_id
, ¿cómo harías para crear esa nueva fila en la tabla Membership? ActiveRecord nos lo pone fácil. Lo que queremos hacer es, para un determinado registro User
, añadirle un ‘membership’, de forma que cuando digamos @user.groups
, nos devuelva una lista de grupos que incluya el grupo que acabamos de añadir. Si haces esto:
#assuming @user is your User [email protected] << Group.find(group_id)#if you have a list of group_ids(something like ), you can also do:@user.group_ids << group_ids
Este trozo de código creará automáticamente una nueva fila en la tabla Membership con los group_id
y user_id
adecuados. Y ahora, cada vez que utilice @user.groups
, obtendrá una lista de los grupos que ha añadido. Para mayor seguridad, prueba lo anterior en tu consola de Rails.
Consulta la guía de Rails para más detalles sobre los métodos que ActiveRecord te proporciona cuando utilizas has_many :through
.
Voy a suponer que tienes algún tipo de autenticación configurada en tu aplicación, que te da acceso al método current_user
. Necesitaremos este método para obtener nuestro user_id
, a través de una simple llamada current_user.id
. Una vez que tengas tu usuario (con algo como @user = User.find(current_user.id)
), puedes usar el código anterior para añadir grupos.
La siguiente pregunta es, ¿cómo escribes tu vista de forma que pase los valores group_id
al controlador?
Cómo escribas tu vista dependerá totalmente del flujo que esperes que hagan tus usuarios y de otros factores de tu app. Digamos que decides proporcionar a tu usuario una lista de casillas de verificación que enumeran los grupos a los que puede unirse o abandonar. Esta es una forma sencilla de conseguirlo:
<% Group.all.each do |group| %> <%= check_box_tag "user", group.id, @user.group_ids.include?(group.id) %> <%= group.name %> <br /><% end %>
El uso de check_box_tag
probablemente necesite alguna explicación.
El primer parámetro "user"
le dice a Rails que agrupe todas las casillas de verificación con este ID y las pase al controlador como un Array. Lo que esto significa es que en tu controlador puedes hacer params
y obtener un bonito Array de Ruby con todos los group_ids
que el usuario ha elegido.
El último parámetro sólo asegura que cualquier Grupo al que el usuario pertenezca en ese momento se marque cuando el formulario se renderice.
Lo anterior debería servirte para empezar a utilizar has_many :through en tu aplicación Rails, pero dependiendo de lo que haga tu aplicación estoy bastante seguro de que te encontrarás con problemas que no están cubiertos en este post. Así que si sigues atascado, echa un vistazo a lo siguiente:
1) Echa un vistazo a este increíble casting de Rails que te lleva a través de toda la gama de uso de has_many :through. Si aún no lo has hecho, te recomiendo que te hagas una cuenta en RailsCasts.
2) Guía de Rails ActiveRecord sobre has_many :through
Deja una respuesta