2009-08-10 9 views
2

je suis novice dans les rails et essayer d'effectuer une jointure gauche dans mysql.gauche rejoindre dans les rails/mysql

Il existe deux objets - utilisateur et message.

messages has_and_belongs_to_many utilisateur, message utilisateurs has_and_belongs_to_many

actuellement, par user.messages simplement écrire i get suivantes requête dans la console

SELECT * FROM `messages` INNER JOIN `messages_users` ON `messages`.id = `messages_users`.message_id WHERE (`users_messages`.group_id = 1) 

message avec restriction == false est pas connecté à un utilisateur, mais accessible par tout utilisateur, et j'ai besoin d'ajouter la collection Message.all (restricted => false) à user.messages

la requête qui permettrait de résoudre mon problème serait:

select * from messages left join messages_users on messages_users.message_id=messages.id and messages_users.user_id=1 where (messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true); 

comment l'écrire dans des rails aussi élégamment que possible?

serait-il smth comme

Message.find(:all,:conditions => "(messages_users.user_id is NULL and messages.restricted=false) OR (messages_users.user_id=1 and messages.restricted=true)", :joins => "left join messages_groups on messages_users.message_id=messages.id and messages_users.user_id=1 ") 

ou peut-il être plus agréable?

J'utilise des rails 2.3.2

, grâce Pavel

Répondre

1

Il me semble que vous essayez de tirer deux choses dans cette requête: 1) tous les messages non liés à un utilisateur avec restricted = false et 2) tous les messages liés à l'utilisateur actuel avec restricted = true.

Si je comprends bien, je ne vois pas une meilleure façon de le faire si vous le voulez en une seule requête. Cependant, si vous êtes ouvert à l'idée de faire deux requêtes, vous pouvez le nettoyer légèrement dans le code (tout en ralentissant éventuellement l'exécution). Voici la configuration de remplacement:

class Message < ActiveRecord:Base 
    has_and_belongs_to_many :users 

    named_scope :restricted, :conditions => {:restricted => true} 
    named_scope :unrestricted, :conditions => {:restricted => false} 
    named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM messages_users)" 
end 

class User < ActiveRecord:Base 
    has_and_belongs_to_many :messages 
end 

Pour obtenir la liste en moins de code, mais nécessitant deux bases de données frappe que vous pouvez faire:

@current_user.messages.restricted + Message.unrestricted.public 

Dans les deux cas, s'il y a une quantité importante de données dans ces les tables dont vous avez besoin pour vous assurer qu'elles sont correctement indexées ou cela va ralentir avec n'importe quelle charge. S'il s'agit d'une application avec beaucoup de messages envoyés, vous êtes probablement mieux avec la requête unique. Si c'est juste une fonction secondaire qui ne sera pas utilisée beaucoup, je prendrais probablement la version plus propre. Ce qui fonctionnerait probablement mieux du point de vue du modèle est de se débarrasser de la relation HABTM et de modéliser explicitement la relation.Ensuite, vous avez un endroit pratique pour garder trace d'autres données sur le processus d'envoi/livraison/réception de message (comme le temps de suivi envoyé, le temps de lecture, etc). Cela ne change rien à la discussion ci-dessus, je préfère juste en avoir beaucoup à HABTM.

class Message < ActiveRecord:Base 

    has_many :subscriptions 
    has_many :users, :through => :subscriptions 

    named_scope :restricted, :conditions => {:restricted => true} 
    named_scope :unrestricted, :conditions => {:restricted => false} 
    named_scope :public, :conditions => "id NOT IN (SELECT DISTINCT message_id FROM subscriptions)" 
end 

class User < ActiveRecord:Base 

    has_many :subscriptions 
    has_many :messages, :through => :subscriptions 

end 

class Subscription < ActiveRecord:Base 

    belongs_to :message 
    belongs_to :user 

end 
0

Je pense que named_scopes pourrait être votre réponse. Dans votre modèle mis quelque chose comme:

named_scope :restricted, :conditions => {:restricted => true} 
named_scope :unrestricted, :conditions => {:restricted => false} 

Ensuite, vous pouvez appeler les choses comme:

Message.restricted 
=> All restricted messages 

User.first.messages.unrestricted 
=> All unrestricted messages belonging to the first user. 

Je crois que ce travail par le biais des associations HABTM.

1

pourquoi ne pas utiliser: include?

+0

... mais ne feraient pas non plus de ": include" également une charge ardente des enregistrements associés, ce qui ne semble pas souhaitable dans la situation actuelle. C'est le problème que j'aimerais résoudre. – Purplejacket