query - Ruby on Rails tiene_muchos a través de relaciones autorreferenciales siguientes/seguidores
rails sql query (2)
Hay una cantidad de publicaciones e hilos en has_many: through, pero no he encontrado ninguno que cubra específicamente lo que estoy tratando de hacer.
Tengo un modelo de Usuario y un modelo de Amistades. Un usuario tiene muchos usuarios que los siguen, así como muchos seguidores. Es el modelo habitual de Twitter.
Para un usuario dado, quiero configurar relaciones de Active Record que devuelvan los usuarios reales que siguen al usuario y que el usuario es seguidor de.
Estas son las relaciones que he configurado:
class User < ActiveRecord::Base
has_many :following, :class_name => ''User'', :through => :friendships, :foreign_key => ''user_id''
has_many :followers, :class_name => ''User'', :through => :friendships, :foreign_key => ''friend_id''
end
class Friendship < ActiveRecord::Base
belongs_to :user
belongs_to :following, :class_name => ''User'', :foreign_key => ''friend_id''
belongs_to :follower, :class_name => ''User'', :foreign_key => ''user_id''
end
La siguiente relación funciona: genera la unión siguiente:
SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.friend_id WHERE ((`friendships`.user_id = 1))
Todo es grandioso
Sin embargo, la relación de seguidor no funciona. Intenté varias variaciones, pero la mayoría parece devolver el mismo conjunto de resultados que Siguientes.
Necesito que la unión se configure de la siguiente manera para devolver el conjunto de resultados correcto.
SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.user_id WHERE ((`friendships`.friend_id = 1));
¿Dónde estoy equivocado?
Puedo configurar esto usando la opción finder_sql en has_many, pero parece que debería haber una mejor manera.
has_many :followers, :class_name => ''User'', :finder_sql => ''SELECT `users`.* FROM `users` INNER JOIN `friendships` ON `users`.id = `friendships`.user_id WHERE ((`friendships`.friend_id = #{ id }))''
¡Gracias!
Hice un poco de progreso y, finalmente, conseguí que la relación funcionara al dividir las relaciones en dos partes, como se muestra en esta respuesta: autorreferencial has_many: a través de personalizado: cuestión de clave principal
# FOLLOWING
has_many :friendships_to, :foreign_key => ''user_id'', :class_name => ''Friendship''
has_many :following, :through => :friendships_to, :class_name => ''User''
# FOLLOWERS
has_many :friendships_from, :foreign_key => ''friend_id'', :class_name => ''Friendship''
has_many :followers, :through => :friendships_from, :class_name => ''User''
Sin embargo, aunque era posible tener una versión de una línea de la relación para seguir
has_many :following, :class_name => ''User'', :through => :friendships, :foreign_key => ''user_id''
Todavía no pude hacer que funcione para los seguidores. ¿Todavía te preguntas cómo se podría hacer esto?
Debe asegurarse de que ActiveRecord sepa cuál es la asociación de origen para los # amigos del usuario y también los seguidores y especifique la clase y la clave foreign_key para las relaciones que ActiveRecord no puede extrapolar de los nombres de las asociaciones.
class Following < ActiveRecord::Base
belongs_to :user
belongs_to :followed, :class_name => ''User''
end
class User < ActiveRecord::Base
has_many :followings
has_many :friends, :through => :followings, :source => ''followed''
has_many :followeds, :class_name => ''Following'', :foreign_key => ''followed_id''
has_many :followers, :through => :followeds, :source => :user
end
Soy un novato en un proceso de aprendizaje, pero estos modelos me parecen más limpios:
class User < ActiveRecord::Base
has_many :followings
has_many :followers, through: :followings
end
class Following < ActiveRecord::Base
belongs_to :user
belongs_to :follower, class_name: ''User''
end
- Source Treehouse: https://www.youtube.com/watch?v=jSUWu50XK48