Una única asociación a través de un a relación N a M y una 1 a N

Hola,

Os cuento mi escenario:

  • Tengo users, que a su vez tienen systems (relación N a M). Se unen a
    través de suscriptions.
  • Los systems tienen alerts (relación 1 a N)

Y las asociaciones son las típicas:

class User < ActiveRecord::Base
has_many :systems, :through => :suscriptions
end

class System < ActiveRecord::Base
has_many :alerts
has_many :suscriptions
has_many :users, :through => :suscriptions
end

class Alert < ActiveRecord::Base
belongs_to :system
end

Mi pregunta es, ¿cuál es la mejor forma de implementar user.alerts?

La primera forma que se me ha ocurrido es incluir el siguiente método
en el modelo user.rb:

def alerts
aa = []
self.systems.map {|s| aa += s.alerts }
return aa
end

Es decir, para cada system del usuario obtengo un array con todas sus
alerts. Lo que devuelvo es la unión de todos estos arrays.

Esta forma no me gusta porque,

  1. no me parece muy elegante
  2. si un user tiene N systems, se generan N+1 queries contra la base de
    datos

¿Qué otras formas se os ocurren? Llevo una rato dándole vueltas. Estoy
convencido de que tiene que haber una manera sencilla.

Muchas gracias,

Javier, no es tampoco muy elegante:

class User < ActiveRecord::Base
has_many :suscriptions
has_many :systems, :through => :suscriptions
has_many :alerts, :finder_sql => ‘SELECT * FROM alerts WHERE
system_id
IN(SELECT system_id FROM suscriptions WHERE user_id = #{self.id})’
end

Me has hecho acordar que llegando a casa tengo que repasar por tercera
vez
la parte de asociaciones en The Rails Way ;).

Saludos.

El día 22 de abril de 2008 13:09, Javier Vidal P.
[email protected]
escribió:

Hay un plugin para poder anidar relaciones has_many con :through :
http://agilewebdevelopment.com/plugins/nested_has_many_through
Con eso deberías poder hacer:

class User < ActiveRecord::Base
has_many :suscriptions
has_many :systems, :through => :suscriptions
has_many :alerts, :through => :systems
end

que queda muy elegante :slight_smile:

HTH
Juanjo

2008/4/22 Ruben. D. [email protected]:

Muchas gracias por vuestras respuestas.

He probado el plugin y funciona muy bien. Genera los dos joins en una
única query sin tener que escribir sql.

Veo que esta funcionalidad se quiere meter en el core:

http://dev.rubyonrails.org/ticket/6461

Genial. Es justo lo que quería. Muchas gracias.

Salu2,

El 22/04/2008, a las 21:45, Juanjo Bazán escribió:

Hay un plugin para poder anidar relaciones has_many con :through : http://agilewebdevelopment.com/plugins/nested_has_many_through
Con eso deberías poder hacer:

class User < ActiveRecord::Base
has_many :suscriptions
has_many :systems, :through => :suscriptions
has_many :alerts, :through => :systems
end

No había caido en esa.

El día 22 de abril de 2008 13:09, Javier Vidal P. <[email protected]

escribió:

  • Tengo users, que a su vez tienen systems (relación N a M). Se unen a
    través de suscriptions.
  • Los systems tienen alerts (relación 1 a N)
    class User < ActiveRecord::Base
    has_many :systems, :through => :suscriptions
    end

Esto es lo que yo hubiese echo:

class User < ActiveRecord::Base
has_many :systems, :through => :suscriptions do
del alerts
return if self.size == 0
Alerts.find(:all, :conditions => “subscription_id IN
(#{self.map(&:id),join(”,“)})”)
end
end
end

No es la panacea, pero te permite hacer

User.find(:first).systemes.alerts que queda bastante elegante :slight_smile:

Un Saludo