2012-05-21 19 views
7

Ho 2 modelliavanzata SQL in Rails

class User < AR 
has_many :friends 
end 

class Friend < AR 
    # has a name column 
end 

Ho bisogno di trovare tutti gli Utenti che sono amici sia con 'Joe' e 'Jack'

Qualsiasi idea di come posso fare questo in Rails?

+0

Mi dispiace, non ho letto abbastanza attentamente la tua domanda ... ha cancellato la mia risposta errata. – Mischa

+0

@muistooshort in sostituzione o con e non funziona –

+0

Hai frainteso la mia correzione all'incomprensione di Mischa, i nostri commenti stavano dicendo la stessa cosa. –

risposta

3

Un'opzione consiste nel mettere ciascuno dei nomi come argomenti per i singoli INNER JOINS. In SQL sarebbe qualcosa di simile:

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' 

Dal momento che è inner join, sarà solo visualizzare i risultati in cui la tabella degli utenti possono essere collegati sia con F1 e F2.

E per usarlo in Rails, forse fare qualcosa di simile:

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 

che poi si potranno chiamare in questo modo:

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

Possibile modo: User.all(:joins => :friends, :conditions => ["friends.name IN (?,?)", "Joe", "Jack"], :group => "users.id") e quindi scorrere l'array per trovare utenti con 2 amici.

Questa è la soluzione migliore che ho trovato quando ho provato a risolvere un problema simile per me stesso. Se trovi il modo di farlo in puro sql o ActiveRecord - fammi sapere per favore!

1

Sebbene l'utilizzo di SQL hard-coded come suggerito da DanneManne molto spesso funzionerà, ed è probabilmente il modo in cui vorresti andare, non è necessariamente componibile. Non appena è stato codificato un nome di tabella, è possibile che si verifichino problemi che lo associno ad altre query in cui ActiveRecord può decidere di eseguire l'alias della tabella.

Così, a costo di una certa complessità in più, possiamo risolvere questo utilizzando alcuni Arel come segue:

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'))) 

Ciò utilizzare un paio di sottoquery per fare il lavoro.

Sono abbastanza certo che ci sia una soluzione ARel che usa anche join, ma e posso capire come comporre quella query in ARel, non solo come usare quella query come base per una query ActiveRecord per tornare indietro Istanze del modello utente.

+0

Questo è ottimo ma questa query esatta non funziona. Guardando altre soluzioni usando questa tecnica. Grazie! –