jointures multiples en utilisant activerecord in rails
-
03-07-2019 - |
Question
Je construis un petit service de microblogging de style Twitter dans lequel les utilisateurs peuvent suivre d'autres utilisateurs et obtenir un flux de leurs messages
J'ai les modèles suivants:
class Follow < ActiveRecord::Base
belongs_to :follower, :class_name => "User"
belongs_to :followee, :class_name => "User"
end
class User < ActiveRecord::Base
has_many :follows, :foreign_key => 'follower_id',
:class_name => 'Follow'
has_many :followers, :through => :follows
has_many :followed, :foreign_key => 'followee_id',
:class_name => 'Follow'
has_many :followees, :through => :followed
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
Pour obtenir un flux pour l'utilisateur actuel, je souhaite exécuter la requête SQL suivante:
SELECT * FROM follows JOIN users JOIN messages WHERE follows.follower_id = current_user.id AND follows.followee_id = users.id AND users.id = messages.user_id;
Quelle est la bonne façon pour cela d’ActiveRecord?
La solution
Je ne sais pas ce que vous cherchez, mais voici ma suggestion:
Je suppose que vous avez d'autres objectifs pour cette classe de suivi, sinon je ne vois pas le but.
La "manière correcte" (c’est-à-dire ma façon totalement subjective) de le faire serait en quelque sorte comme ceci:
class User < ActiveRecord::Base
has_and_belongs_to_many :followers, :foreign_key => 'followed_id',
:class_name => 'User', :association_foreign_key => 'follower_id',
:include => [:messages]
has_and_belongs_to_many :follows, :foreign_key => 'follower_id',
:class_name => 'User', :association_foreign_key => 'followed_id'
has_many :messages
end
class Message < ActiveRecord::Base
belongs_to :user
end
Créez ensuite le tableau suivant:
create_table :users_users, :id => false do |t|
t.integer :followed_id
t.integer :follower_id
end
Et vous êtes prêt:
followed = User.find :first
follower = User.find :last
followed.followers << follower
followed.followers.first.messages
followed.followers.first.followers.first.messages # etc...
Mais de ce que je fais, vous voulez afficher tous les messages de tous les abonnés en même temps.
Cela devrait être possible en ajoutant
has_and_belongs_to_many :followed_messages, :foreign_key => 'follower_id',
:class_name => 'Message', :association_foreign_key => 'followed_id'
à la classe Utilisateur , mais je ne sais pas à quel point cela serait correct. Ou bien, il serait peut-être possible d’obtenir des extensions d’association, mais je ne peux pas vraiment donner d’exemples.
Mise à jour:
En modifiant: nom_classe, il sera associé au Message.id
, n'y a pas pensé, donc ce ne sera pas correct de cette façon.
Donc, le seul "sympa" L’option est de passer par la classe User comme dans le premier exemple. Les seules autres options que je peux voir sont les extensions d’association (pour lesquelles je ne peux pas vous donner d’exemple) ou peut-être une déclaration finder.
has_many :followed_messages, :class_name => 'Message',
:finder_sql => 'select * from messages where user_id in(select followed_id from users_users where follower_id = #{id})'
Vous devez probablement personnaliser cette instruction SQL pour que tout fonctionne, mais au moins vous devriez obtenir l'image :)
Autres conseils
L'arrangement de Keijro fonctionnerait mieux, mais si vous avez besoin de la table Follow, vous pouvez alors exécuter la requête SQL spécifiée comme suit:
Follow.all(:joins => { :messages, :users }, :conditions => { "follows.follower_id" => current_user.id, "follows.followee_id" => "users.id", "users.id" => "messages.user_id"} )