2012-05-21 18 views
7

tengo 2 modelosavanzada SQL en rieles

class User < AR 
has_many :friends 
end 

class Friend < AR 
    # has a name column 
end 

Necesito encontrar todos los usuarios que son amigos de ambos 'Joe' y 'Jack'

alguna idea de cómo puedo hacer esto en los carriles?

+0

Disculpa, no leí tu pregunta con cuidado ... eliminé mi respuesta incorrecta. – Mischa

+0

@muistooshort reemplazando o por y no funciona –

+0

Ha malinterpretado mi corrección al malentendido de Mischa, nuestros comentarios decían lo mismo. –

Respuesta

3

Una opción es poner cada uno de los nombres como argumentos para UNIONES INTERNAS individuales. En SQL sería algo como esto:

SELECT users.* FROM users 
INNER JOIN friends AS f1 
    ON users.id = f1.user_id 
    AND f1.name = 'Joe' 
INNER JOIN friends AS f2 
    ON users.id = f2.user_id 
    AND f2.name = 'Jack' 

Dado que es combinaciones internas, que sólo mostrará los resultados en la tabla de usuarios se pueden unir con las dos f1 y f2.

Y para utilizarlo en rieles, tal vez hacer que algo como esto:

class User < AR 
    has_many :friends 

    def self.who_knows(*friend_names) 
    joins((1..friend_names.length).map{ |n| 
     "INNER JOIN friends AS f#{n} ON users.id = f#{n}.user_id AND f#{n}.name = ?" }.join(" "), 
     *friend_names) 
    }) 
    end 
end 

que luego se puede llamar así:

@users = User.who_knows("Joe", "Jack") 
1

Posible forma: User.all(:joins => :friends, :conditions => ["friends.name IN (?,?)", "Joe", "Jack"], :group => "users.id") y luego iterar sobre la matriz para buscar usuarios con 2 amigos.

Esta es la mejor solución que obtuve cuando intenté resolver un problema similar para mí. Si encuentra la forma de hacerlo en sql puro o ActiveRecord, avíseme por favor.

1

Aunque el uso de SQL modificable según lo sugerido por DanneManne con mayor frecuencia funcionará, y es probablemente la forma en que desearía ir, no es necesariamente composable. Tan pronto como haya codificado un nombre de tabla, puede tener problemas para combinarlo en otras consultas donde ActiveRecord puede decidir alias de la tabla.

Así, a costa de cierta complejidad adicional, podemos resolver esta utilizando algún Arel de la siguiente manera:

f = Friend.arel_table 
User. 
    where(:id=>f.project(:user_id).where(f[:name].eq('Joe'))). 
    where(:id=>f.project(:user_id).where(f[:name].eq('Jack'))) 

Esto utilizará un par de sub consultas para hacer el trabajo.

Estoy bastante seguro de que hay una solución de ARel utilizando combinaciones también, pero puedo encontrar la forma de redactar esa consulta en ARel, pero no cómo usar esa consulta como base para una consulta ActiveRecord para volver Instancias de modelo de usuario.

+0

Esto es genial, pero esta consulta exacta no está funcionando. Mirando otras soluciones usando esta técnica. ¡Gracias! –