2010-01-25 5 views
1

J'ai créé une application qui trouve des fournisseurs de services basés sur plusieurs services qui lui sont passés. Ceci est fait via a many_through donc il y a un objet join. Fondamentalement, si un utilisateur demande des fournisseurs de services avec le service A et le service B, ma portée renvoie les fournisseurs de services qui offrent à la fois le service A et le service B ou d'autres fournisseurs de services qui fournissent le service A ou le service B. Limitez-le aux seuls fournisseurs qui fournissent les DEUX services.Comment créer une requête exclusive plutôt qu'inclusive avec des étendues nommées dans Rails?

Mon champ ressemble à ceci:

named_scope :with_services, lambda { |services| { 
     :conditions => ["services.id IN (#{services.map{|s| s.id}.join(', ')}) 
         AND service_options.service_owner_type='ServiceProvider' 
         AND service_options.service_owner_id = service_providers.id"], 
     :include => [:services, :service_options] 
    } 
    } 

Comme vous pouvez le voir, je suis en utilisant l'opérateur IN pour ce faire. Mais IN, c'est comme si on disait: «Amenez-moi un fournisseur qui a un service A ou un service B» alors que ce que je veux vraiment, c'est: «Trouvez-moi un fournisseur de services qui a le service A et le service B.

Est-il possible de faire ce type de filtrage dans une seule requête ou est-ce que je devrais faire une requête composée ou simplement parcourir les résultats et les retirer de la liste s'ils ne supportent pas tous les services requis?

Répondre

1

Je pense que vous pouvez probablement le faire en fournissant la liste des services pour chacun des services A et B.

donc soit modifier la portée de prendre deux listes:

:conditions => ["services.id IN (service_a) AND services.id IN (service_b)"] 

Vous pourriez même en fait être en mesure d'appeler la portée deux fois

Model.with_services(service_a).with_services(service_b) 

également sans frais supplémentaires, vous pouvez sténographie votre manipulation de tableau pour trouver les ids:

services.collect(&:id).join 

&: id est l'équivalent d'un bloc à l'aide « | o | o.id "

+0

Merci, je vais donner un coup de feu. Un problème que j'ai oublié de mentionner dans la question est que cela est variable.Vous pourriez avoir 1 service ou 5 services passés. Serait la meilleure méthode être de mapper les services et de générer cet extrait de SQL? Comme ceci: : conditions => ["# {services.map {| s | 'services.id IN (' + s.id + ')}. join (' AND ')} ... "] –

+0

Malheureusement, lorsque j'essaie cette méthode, je suis nul. Je crois que c'est parce qu'un ID donné ne peut pas être égal ou à IN deux valeurs mutuellement exclusives.Il semble que cela nécessite presque une requête composée.Il suffit d'utiliser une boucle for pour analyser les résultats: - \ –

Questions connexes