Question

Je suis débutant dans des rails et essayer de réaliser gauche se joindre à MySQL.

il y a deux objets - l'utilisateur et le message.

Messages has_and_belongs_to_many utilisateur, les utilisateurs de messages has_and_belongs_to_many

actuellement, par user.messages simplement écrire que je reçois requête suivante 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 restreint == false n'est pas connecté à tout utilisateur, mais est accessible par tous les utilisateurs, et je besoin d'ajouter la collection Message.all (limitée => false) à user.messages

la requête qui résoudrait 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 puis-je l'écrire dans des rails le plus élégamment 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 rails 2.3.2

merci, Pavel

Était-ce utile?

La solution

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

Si je comprends bien que, je ne vois pas une meilleure façon de le faire si vous voulez le faire en une seule requête. Toutefois, si vous êtes ouvert à l'idée d'en faire deux requêtes, vous pouvez nettoyer un peu dans le code (tout peut ralentir 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 dans le code moins, mais nécessitant deux bases de données que vous pouvez faire frappe:

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

Dans les deux cas, s'il y a une quantité importante de données dans ces tableaux, vous devez vous assurer qu'ils sont correctement indexés ou cela va ralentir avec toute charge. Si cela est une application avec beaucoup de messages envoyés, vous êtes probablement mieux avec la seule requête. Si c'est juste une fonction secondaire qui ne sera pas utilisé beaucoup, je prendrais probablement la version plus propre.

Qu'est-ce qui probablement mieux du point de vue du modèle est de se débarrasser de la relation HABTM et modéliser la relation explicite. Ensuite, vous avez un endroit pratique pour garder la trace d'autres données sur le message envoi / livraison / processus de réception (comme le suivi du temps envoyé, lecture de temps, etc.). Il ne change pas de la discussion ci-dessus, je préfère a beaucoup à travers 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

Autres conseils

pourquoi ne pas utiliser: include

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.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top