2011-03-21 11 views
8

tengo un modelo simple comoRieles: unirse con múltiples condiciones

class Interest < ActiveRecord::Base 
    has_and_belongs_to_many :user_profiles 
end 

class UserProfile < ActiveRecord::Base 
    has_and_belongs_to_many :interests 
end 

Cuando quiero consultar todos los usuarios con un interés específico, que es bastante sencillo de hacer

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

pero ¿cómo puedo buscar usuarios que tienen intereses múltiples? Por supuesto, si lo hago

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

siempre me dan un resultado vacío, ya que después de la unión, ninguna fila puede tener simultáneamente interest.id = an_interest y interest.id = another_interest.

¿Hay una manera de ActiveRecord para expresar "Quiero la lista de usuarios que tienen 2 intereses (especificados) asociado?

de actualización (solución) que es la primera versión de trabajo que se me ocurrió, felicitaciones a 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 

Respuesta

4

en no es bueno - es una O como expresión

lo que se necesita hacer es tener varias combinaciones en escrito 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 

Es posible que necesite cambiar la cláusula main_join para que se ajuste a sus necesidades.

+0

¡Eso es mucho más complicado de lo que esperaba :)! Pero definitivamente me apuntaste en la dirección correcta. Gracias. La única diferencia es que tuve que 'internal join interests_user_profiles' en lugar de' intereses de unión interna' como escribiste. –

+0

... y también reemplaza 'intereses _ # {idx} .id =?' Con 'intereses _ # {idx} .interest_id =?' –

+0

ah bien - ¿fue una fusión M-a-M? eso tendría sentido, ¡lo siento, no leí tan poco! :RE –

2

Esto hará que los usuarios que tienen al menos una de las categorías económicas contempladas.

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

a GE t usuarios que tienen tanto los intereses especificados probablemente haría algo como esto:

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 

No es increíblemente eficiente, pero debe hacer lo que tiene?

+0

Intenté 'UserProfile.joins (: interest) .where (" interests.id =? ", [25, 26])' pero no funcionó –

+0

No, todavía no funciona. Obtengo un error de sintaxis en la consulta 'SELECT 'user_profiles". * FROM "user_profiles" INNER JOIN "interests_user_profiles" EN "interests_user_profiles". "User_profile_id" = "user_profiles". "Id" INNER ÚNASE "intereses" en "intereses". "id" = "interests_user_profiles". "interest_id" WHERE (interests.id = 25,26) ' –

+0

Acabo de leer su comentario en otra respuesta - No me di cuenta de que necesitaba un AND lógico. Mi respuesta hará un OR. – Ant

0

Trate IN (?) y una matriz:

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

la cláusula IN hace un OR lógico (tiene un interés o el otro o ambos) ... Necesito un Y lógico (tiene todos los intereses) –

Cuestiones relacionadas