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?

¿Fue útil?

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.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top