through rails many how has_and_belongs_to_many has foreign example create belongs and active ruby-on-rails associations has-many-through

ruby on rails - how - Ruby-on-Rails: Multiple has_many: a través de posible?



rails foreign key (4)

¿Es posible tener múltiples has_many :through relaciones que se cruzan en Rails? Recibí la sugerencia de hacerlo como una solución para otra pregunta que publiqué, pero no pude hacerlo funcionar.

Los amigos son una asociación cíclica a través de una tabla de unión. El objetivo es crear un has_many :through de friends_comments , para que pueda tomar un User y hacer algo como user.friends_comments para obtener todos los comentarios realizados por sus amigos en una sola consulta.

class User has_many :friendships has_many :friends, :through => :friendships, :conditions => "status = #{Friendship::FULL}" has_many :comments has_many :friends_comments, :through => :friends, :source => :comments end class Friendship < ActiveRecord::Base belongs_to :user belongs_to :friend, :class_name => "User", :foreign_key => "friend_id" end

Esto se ve muy bien, y tiene sentido, pero no funciona para mí. Este es el error que recibo en la parte relevante cuando intento acceder a los comentarios de amigos de un usuario:
ERROR: column users.user_id does not exist
: SELECT "comments".* FROM "comments" INNER JOIN "users" ON "comments".user_id = "users".id WHERE (("users".user_id = 1) AND ((status = 2)))

Cuando acabo de ingresar user.friends, que funciona, esta es la consulta que ejecuta:
: SELECT "users".* FROM "users" INNER JOIN "friendships" ON "users".id = "friendships".friend_id WHERE (("friendships".user_id = 1) AND ((status = 2)))

Por lo tanto, parece que se está olvidando por completo de la relación original has_many través de la amistad, y luego está tratando de usar inapropiadamente la clase User como una tabla de unión.

¿Estoy haciendo algo mal o simplemente no es posible?


Aunque esto no funcionó en el pasado, ahora funciona bien en Rails 3.1.



Hay un complemento que resuelve su problema, eche un vistazo a este blog .

Instala el plugin con

script/plugin install git://github.com/ianwhite/nested_has_many_through.git


Editar:

Rails 3.1 soporta asociaciones anidadas. P.ej:

has_many :tasks has_many :assigments, :through => :tasks has_many :users, :through => :assignments

No hay necesidad de la solución dada a continuación. Consulte this screencast para más detalles.

Respuesta original

Estás pasando un has_many :through asociación como fuente para otro has_many :through asociación. No creo que funcione.

has_many :friends, :through => :friendships, :conditions => "status = #{Friendship::FULL}" has_many :friends_comments, :through => :friends, :source => :comments

Tienes tres enfoques para resolver este problema.

1) Escribir una extensión de asociación

has_many :friends, :through => :friendships, :conditions => "status = #{Friendship::FULL}" do def comments(reload=false) @comments = nil if reload @comments ||=Comment.find_all_by_user_id(map(&:id)) end end

Ahora puedes obtener los comentarios de los amigos de la siguiente manera:

user.friends.comments

2) Agregar un método a la clase de User .

def friends_comments(reload=false) @friends_comments = nil if reload @friends_comments ||=Comment.find_all_by_user_id(self.friend_ids) end

Ahora puedes obtener los comentarios de los amigos de la siguiente manera:

user.friends_comments

3) Si quieres que esto sea aún más eficiente, entonces:

def friends_comments(reload=false) @friends_comments = nil if reload @friends_comments ||=Comment.all( :joins => "JOIN (SELECT friend_id AS user_id FROM friendships WHERE user_id = #{self.id} ) AS friends ON comments.user_id = friends.user_id") end

Ahora puedes obtener los comentarios de los amigos de la siguiente manera:

user.friends_comments

Todos los métodos almacenan en caché los resultados. Si quieres recargar los resultados haz lo siguiente:

user.friends_comments(true) user.friends.comments(true)

O mejor aún:

user.friends_comments(:reload) user.friends.comments(:reload)