Me matan las relaciones n a n


#1

ando bastante liado con este tipo de relaciones ya que no se cual es la
mejor manera de tratar con ellas.

  1. por un lado la relación entre las tablas se puede realizar (ejemplo
    de usuarios y grupos)
    modelo grupos
    has_and_belongs_to_many :usuarios

modelo usuario
has_and_belongs_to_many :grupos

y una tabla intermedia usuario_grupos con usuario_id y grupo_id

  1. otra forma de relacionarlas ya que estoy con REST es la que he usado
    y según he leído en un post de la lista seria tratando la pertenencia
    con un modelo mas que seria usuario_grupo
    modelo grupo
    has_many : usuariogrupos
    has_many :users, :through => : usuariogrupos

modelo usuario
has_many :usuariogrupos
has_many :grupos, :through => : usuariogrupos

modelo usuario_grupo
belongs_to :usuario
belongs_to :grupo

¿Cuando es mejor usar una forma y cuando otra?

Con la segunda forma al hacer por ejemplo
@usuariosgrupos = UsuarioGrupo.find( :all )

@usuariosgrupos.each do |u|
Usuario.find( u.usuario_id.nombre )
Grupo.find( u.grupo_id.nombre )

¿esto no cargaría en exceso la base de datos ya que son muchas
consultas?
¿no se podria hacer un find del modelo usuario_grupo y obtener ya todos
los datos?

otro inconveniente que me he encontrado a sido a la hora de eliminar una
pertenencia ya que la tabla usuario_grupos no contiene un id automatico
no se puede hacer un usuario_grupo_path( id ), :method => :delete
¿esto como se puede solucionar?

Vaya liada y rollo que he soltado y que de preguntas, espero haberme
explicado bien,

Muchas gracias por la ayuda.
Un saludo.
Aitor.


#2

Aitor escribió:

has_many :usuariogrupos
has_many :grupos, :through => : usuariogrupos

modelo usuario_grupo
belongs_to :usuario
belongs_to :grupo

¿Cuando es mejor usar una forma y cuando otra?

Siguiendo con tus modelos:

            M:N

Usuario —<>---- Grupo

Con el método 1(HABTM) sólo podrás almacenar la pertenencia de usuarios
a grupos o viceversa, sin ninguna información extra a parte de la que te
proporcione el usuario o el grupo.

Si necesitaras por ejemplo saber la fecha de entrada de los usuarios en
los grupos la relación sería algo tal que así:

            M:N

Usuario —<>---- Grupo
|
*Fecha

(Siendo fecha un atributo de la tabla M-N que relaciona Usuario y
Grupo.)

Entonces en este caso sí que necesitarías el método 2 (through).

Resumiendo:
Si solo necesitas saber que hay relación entre 2 modelos puedes usar
HABTM.
Si necesitas almacenar información extra en la tabla “intermedia”
through.

Saludos!


Rafael Garcia Ortega

Prueba gratis nuestro nuevo producto GASTOSgem
(http://www.gastosgem.com)


#3
            M:N

Usuario —<>---- Grupo
|
*Fecha

(Siendo fecha un atributo de la tabla M-N que relaciona Usuario y Grupo.)

Lo especifiqué debajo con el comentario por si acaso no se veía bien y
efectivamente no se vio bien.
El atributo fecha saldría de los <>


Rafael Garcia Ortega

Prueba gratis nuestro nuevo producto GASTOSgem
(http://www.gastosgem.com)


#4

On 08/06/07, aitor removed_email_address@domain.invalid wrote:

gracias por la explicación,
al final lo estoy realizando con la segunda forma comentada usando
:through y añadiendo un id autonumerico a la tabla intermedia para así
poder usar rest.

Si es así, es más elegante que el modelo “intermedio” tenga un nombre
más apropiado que usuariogrupo, como por ejemplo “pertenencia” Así
creas “pertenencias”, editas “pertenencias”, etc.

En Latinoamérica dirían “membresía”, que a mi me suena muy bien también :wink:


Manuel, que
piensa que eres una excelente persona y medra en torno a
http://simplelogica.net y/o http://simplelogica.net/logicola/
Recuerda comer mucha fruta y verdura.


#5

gracias por la explicación,
al final lo estoy realizando con la segunda forma comentada usando
:through y añadiendo un id autonumerico a la tabla intermedia para así
poder usar rest.

un saludo.


#6

On 6/7/07, Aitor removed_email_address@domain.invalid wrote:

y una tabla intermedia usuario_grupos con usuario_id y grupo_id

El correcto nombre seria grupos_usuarios ambos en plural y puestos en
orden alfabetico.

has_many :grupos, :through => : usuariogrupos

@usuariosgrupos.each do |u|
Usuario.find( u.usuario_id.nombre )
Grupo.find( u.grupo_id.nombre )

¿esto no cargaría en exceso la base de datos ya que son muchas
consultas?
¿no se podria hacer un find del modelo usuario_grupo y obtener ya todos
los datos?

Si queres traer todos los datos con relaciones incluidas tenes que
usar :include. Por ejemplo:
cats=Category.find :all, :include => :products

Ahi realiza una consulta donde trae las categorias y a la vez los
productos relacionados con esas categorias.

otro inconveniente que me he encontrado a sido a la hora de eliminar una
pertenencia ya que la tabla usuario_grupos no contiene un id automatico
no se puede hacer un usuario_grupo_path( id ), :method => :delete
¿esto como se puede solucionar?

Si te referis a que cuando borres un elemento de una clase borres las
dependencias tambien eso se puede especificar con :dependent.

Vaya liada y rollo que he soltado y que de preguntas, espero haberme
explicado bien,

Muchas gracias por la ayuda.
Un saludo.
Aitor.

Te explico a mi entender:

Cuando vos tenes 2 tablas las cuales estan en una relacion n x n,
surge una tabla en el medio que tiene los id y eso que veo que ya
entendes. Esa tabla posee solo los ids y el nombre es como te
explique.

Esa tabla en tu modelo no existe, es solo una tabla que va a guardar
relaciones y lo mantiene rails por detras de la escena. La tabla sera
usada para hacer joins.

Ahora suponiendo que vos tenes una tabla que ademas de relaciones 2
tablas con sus ids tiene otro atributo por ejemplo: usuarios y
empresas, n a n pero ademas en un usuario tiene un rol en una empresa,
esta 3ra tabla pasa a ser parte de tu modelo porque ademas de
relacionar 2 tablas tiene un atributo. La tabla esta por ejemplo
podria ser empleos.

Hay un caso bien explicado en “Agile development…”

Saludos!