2009-09-07 17 views
0

J'essaye de créer une portée nommée comme User.not_in_project(project) mais je ne peux pas trouver la bonne manière.Complicated named_scope: Trouver des utilisateurs qui n'appartiennent pas à un certain projet

J'ai des utilisateurs, projets et devoirs en tant que modèle se joindre à:

class User < ActiveRecord::Base 
    has_many :duties, :extend => FindByAssociatedExtension 
    has_many :projects, :through => :duties 
end 

class Duty < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :project 
end 

class Project < ActiveRecord::Base 
    has_many :duties 
    has_many :users, :through => :duties 
end 

J'ai essayé avec un named_scope similaire à cette clause trouver:

User.all(:joins => :duties, :conditions => ['duties.project_id != ?', my_project]) 

Mais cela ne me retourne pas les utilisateurs qui n'ont pas my_project mais les utilisateurs qui ont un projet autre que my_project.

En d'autres termes, je veux que le champ nommé de se comporter exactement comme cette méthode:

def self.not_present_in p 
    self.all.reject{|u| u.projects.include?(p)} 
end 

Comment puis-je faire cela?

+0

Que voulez-vous récupérer? Je ne suis pas clair à ce sujet. –

+0

Je veux une portée nommée qui se comporte exactement comme cette méthode: def self.not_present_in p self.all.reject {| u.projects.include? (p)} end Je veux qu'il retourne les utilisateurs qui n'ont pas de projet passé en argument. Aidez-nous? –

+0

J'ai édité la question pour contenir la clarification ci-dessus car elle contient le code source. –

Répondre

1

Penser dans SQL, la requête doit être quelque chose comme:

select id 
    from users 
where id not in (select id 
        from users join duties on users.id = duties.user_id 
        join projects on duties.project_id = projects.id 
        where projects.id = %) 

Mais je ne suis pas trop sûr de savoir comment cela fonctionnerait à l'aide named_scope. Je dirais utiliser quelque chose comme

def self.not_present_in p 
    find_by_sql ["select id from users where id not in (select id from users join duties on users.id = duties.user_id join projects on duties.project_id = projects.id where projects.id = ?)", p] 
end 

Pas aussi joli qu'utilisant AR, mais fonctionnera (et vous sauvera quelques questions, probablement).

+0

Merci Yaraher, la requête sql que vous fournissez fonctionne comme je le souhaite avec un correctif mineur. J'ai dû substituer "id" avec "users.id" après la deuxième sélection pour ne pas être ambigu. Cependant, je ne peux pas utiliser find_by_sql dans un named_scope :(. –

+0

Mais pourquoi avez-vous besoin d'être un champ nommé? Pour fusionner avec une autre méthodes? moins que ce soit le cas, il devrait fonctionner correctement. Et Si vous voulez l'affiner un peu plus tard, vous pouvez toujours soumettre un hash d'options similaire à celui qu'utilise AR, et le concaténer/fusionner avec la requête find_by_sql.Peut-être un peu de travail supplémentaire, mais il sera probablement aussi proche que vous Les ORM ne nous empêchent pas toujours d'utiliser SQL :) – Yaraher