Ruby-on-rails: has_many múltiple: a través posible?
-
24-09-2019 - |
Pregunta
¿Es posible tener múltiples relaciones has_many :through
que pasan a través de uno al otro en los carriles? He recibido la sugerencia de hacerlo como una solución para la otra pregunta que he publicado, pero han sido incapaces de conseguir que funcione.
Amigos son un asociación cíclica a través de una tabla de unión. El objetivo es crear un has_many :through
para friends_comments
, para que pueda tomar una User
y hacer algo como user.friends_comments
para obtener todos los comentarios hechos 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 está funcionando para mí. Este es el error que estoy recibiendo en su parte pertinente cuando intento acceder a la friends_comments 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 acaba de entrar en user.friends, que funciona, esto es la consulta se 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 es totalmente olvidándose de la has_many
original a través de la relación de amistad, y luego está tratando de forma inapropiada a utilizar la clase de usuario como una tabla de unión.
¿Estoy haciendo algo mal, o se trata simplemente no es posible?
Solución
Editar
Carriles 3.1 soportes asociaciones anidados. Por ejemplo:
has_many :tasks
has_many :assigments, :through => :tasks
has_many :users, :through => :assignments
No hay necesidad de que la solución dada a continuación. Consulte el este screencast para más detalles.
Respuesta original
Está pasando una asociación has_many :through
como fuente para otro has_many :through
asociación. No creo que va a funcionar.
has_many :friends,
:through => :friendships,
:conditions => "status = #{Friendship::FULL}"
has_many :friends_comments, :through => :friends, :source => :comments
Hay tres enfoques para resolver este problema.
1) escribir una extensión 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 usted puede conseguir los Comentarios de la siguiente manera:
user.friends.comments
2) Añadir un método de la clase User
.
def friends_comments(reload=false)
@friends_comments = nil if reload
@friends_comments ||=Comment.find_all_by_user_id(self.friend_ids)
end
Ahora usted puede conseguir los Comentarios de la siguiente manera:
user.friends_comments
3) Si desea que esto sea aún más eficiente a continuación:
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 usted puede conseguir los Comentarios de la siguiente manera:
user.friends_comments
Todos los métodos de caché de los resultados. Si desea volver a cargar los resultados de hacer lo siguiente:
user.friends_comments(true)
user.friends.comments(true)
o mejor aún:
user.friends_comments(:reload)
user.friends.comments(:reload)
Otros consejos
Hay un plugin que resuelve su problema, echar un vistazo a este blog .
Se instala el plugin con
script/plugin install git://github.com/ianwhite/nested_has_many_through.git
A pesar de que esto no funcionó en el pasado, que funciona bien en Rails 3.1 ahora.
He encontrado esta entrada de blog para ser útil: http://geoff.evason.name/2010/04/23/nested-has_many-through-in-rails-or-how-to-do- a-3-table-join /