Respuestas:
Digamos que tiene dos modelos: User
y Group
.
Si desea que los usuarios pertenezcan a grupos, puede hacer algo como esto:
class Group < ActiveRecord::Base
has_many :users
end
class User < ActiveRecord::Base
belongs_to :group
end
¿Qué sucede si desea realizar un seguimiento de metadatos adicionales en torno a la asociación? Por ejemplo, cuando el usuario se unió al grupo, o ¿cuál es el rol del usuario en el grupo?
Aquí es donde hace que la asociación sea un objeto de primera clase:
class GroupMembership < ActiveRecord::Base
belongs_to :user
belongs_to :group
# has attributes for date_joined and role
end
Esto introduce una nueva tabla y elimina la group_id
columna de la tabla del usuario.
El problema con este código es que tendría que actualizar cada vez que use la clase de usuario y cambiarla:
user.groups.first.name
# becomes
user.group_memberships.first.group.name
Este tipo de código apesta, y hace que la introducción de cambios como este sea dolorosa.
has_many :through
te ofrece lo mejor de ambos mundos:
class User < ActiveRecord::Base
has_many :groups, :through => :group_memberships # Edit :needs to be plural same as the has_many relationship
has_many :group_memberships
end
Ahora puede tratarlo como algo normal has_many
, pero obtenga el beneficio del modelo de asociación cuando lo necesite.
Tenga en cuenta que también puede hacer esto con has_one
.
Editar: facilitando la adición de un usuario a un grupo
def add_group(group, role = "member")
self.group_associations.build(:group => group, :role => role)
end
user.groups << group
? ¿O todo lo maneja esta asociación?
Digamos que tienes estos modelos:
Car
Engine
Piston
Un automóvil has_one :engine
Un motor belongs_to :car
Un motor has_many :pistons
Pistónbelongs_to :engine
Un coche has_many :pistons, through: :engine
pistónhas_one :car, through: :engine
Esencialmente, está delegando una relación de modelo a otro modelo, por lo que en lugar de tener que llamar car.engine.pistons
, simplemente puede hacercar.pistons
has_many :through
y las has_and_belongs_to_many
relaciones funcionan a través de una tabla de unión , que es una tabla intermedia que representa la relación entre otras tablas. A diferencia de una consulta JOIN, los datos se almacenan en una tabla.
Con has_and_belongs_to_many
, no necesita una clave principal y accede a los registros a través de las relaciones ActiveRecord en lugar de a través de un modelo ActiveRecord. Por lo general, utiliza HABTM cuando desea vincular dos modelos con una relación de muchos a muchos.
Utiliza una has_many :through
relación cuando desea interactuar con la tabla de unión como un modelo Rails, completa con claves primarias y la capacidad de agregar columnas personalizadas a los datos unidos. Esto último es particularmente importante para los datos que son relevantes para las filas unidas, pero que en realidad no pertenecen a los modelos relacionados, por ejemplo, almacenar un valor calculado derivado de los campos en la fila unida.
En A Guide to Active Record Associations , la recomendación dice:
La regla general más simple es que debe configurar una relación has_many: through si necesita trabajar con el modelo de relación como una entidad independiente. Si no necesita hacer nada con el modelo de relación, puede ser más sencillo configurar una relación has_and_belongs_to_many (aunque deberá recordar crear la tabla de unión en la base de datos).
Debe usar has_many: through si necesita validaciones, devoluciones de llamada o atributos adicionales en el modelo de combinación.
user
modelo para agregar el grupo. Algo así como la edición que acabo de hacer. Espero que esto ayude.