2011-03-21 3 views
8

j'ai un modèle simple commeRails: se joindre à plusieurs conditions

class Interest < ActiveRecord::Base 
    has_and_belongs_to_many :user_profiles 
end 

class UserProfile < ActiveRecord::Base 
    has_and_belongs_to_many :interests 
end 

Quand je veux interroger tous les utilisateurs ayant un intérêt spécifique, ce qui est assez simple à faire

UserProfile.joins(:interests).where('interests.id = ?', an_interest) 

Mais comment chercher des utilisateurs qui ont des intérêts multiples? Bien sûr, si je

UserProfile.joins(:interests).where('interests.id = ?', an_interest).where('interests.id = ?', another_interest) 

Je reçois toujours un résultat vide, car après la jointure, aucune ligne ne peut avoir en même temps interest.id = an_interest et interest.id = another_interest.

est-il un moyen ActiveRecord d'exprimer « Je veux la liste des utilisateurs qui ont 2 intérêts (spécifié) associé?

mise à jour (solution) qui est la première version de travail je suis venu, bravo à Omar Qureshi

specified_interests.each_with_index do |i, idx| 
     main_join_clause = "interests_#{idx}.user_profile_id = user_profiles.id" 
     join_clause = sanitize_sql_array ["inner join interests_user_profiles interests_#{idx} on 
        (#{main_join_clause} and interests_#{idx}.interest_id = ?)", i] 

     relation = relation.joins(join_clause) 
    end 

Répondre

4

en est pas bon - c'est un OU comme l'expression

ce que vous devez faire est d'avoir plusieurs jointures écrit sur longhanded

(?)
profiles = UserProfile 
interest_ids.each_with_index do |i, idx| 
    main_join_clause = "interests_#{idx}.user_profile_id = user_profiles.id" 
    join_clause = sanitize_sql_array ["inner join interests interests_#{idx} on 
         (#{main_join_clause} and interests_#{idx}.id = ?)", i] 
    profiles = profiles.join(join_clause) 
end 
profiles 

Vous devrez peut-être modifier la clause main_join_clause en fonction de vos besoins.

+0

C'est beaucoup plus compliqué que j'espérais :)! Mais vous m'avez certainement indiqué la bonne direction. Merci. La seule différence est que je devais 'inner join interests_user_profiles' plutôt que' inner join interests' comme vous l'avez écrit. –

+0

... et remplacez aussi 'interests _ # {idx} .id =?' Par 'interests _ # {idx} .interest_id =?' –

+0

ah à droite - c'était une jointure M-to-M? cela aurait du sens, désolé n'a pas lu ce morceau! :RÉ –

2

Cela amener les utilisateurs qui ont au moins l'un des intérêts spécifiques.

UserProfile.joins(:interests).where(:id => [an_interest_id, another_interest_id]) 

Pour ge t les utilisateurs qui ont à la fois des intérêts spécifiques que je ferais probablement quelque chose comme ceci:

def self.all_with_interests(interest_1, interest_2) 
    users_1 = UserProfile.where("interests.id = ?", interest_1.id) 
    users_2 = UserProfile.where("interests.id = ?", interest_2.id) 

    users_1 & users_2 
end 

Pas étonnamment efficace, mais il faut faire ce que vous avez besoin?

+0

J'ai essayé 'UserProfile.joins (: intérêts) .where (" interests.id =? ", [25, 26])' mais cela n'a pas fonctionné –

+0

Non, cela ne fonctionne toujours pas. J'obtiens une erreur de syntaxe dans la requête 'SELECT" user_profiles ". * DE" user_profiles "INNER JOIN" interests_user_profiles "ON" interests_user_profiles "." User_profile_id "=" user_profiles "." Id "INTERNE JOIN" intérêts "ON" intérêts ". "id" = "interests_user_profiles". "interest_id" O WH (interests.id = 25,26) ' –

+0

Je viens de lire votre commentaire sur une autre réponse - je n'avais pas réalisé que vous aviez besoin d'un AND logique. Ma réponse fera un OU. – Ant

0

Essayez IN (?) et un tableau:

UserProfile.joins(:interests).where('interests.id IN (?)', [1,2,3,4,5]) 
+1

la clause IN fait un OU logique (a un intérêt ou l'autre ou les deux) ... J'ai besoin d'un ET logique (a tous les intérêts) –

Questions connexes