Brug af arel
kan få dig ret langt. Den vanskelige del er, hvordan du ikke skriver hele din forespørgsel ved hjælp af arel
's egen forespørgselssyntaks?
Her er et trick:når du bygger din forespørgsel ved hjælp af where
, hvis du bruger arel
betingelser, får du nogle ekstra metoder gratis. For eksempel kan du tilpasse den underforespørgsel, du har der, med .exists.not
, som vil give dig en (NOT ( EXISTS (subquery)))
Smid det ind i forældrenes where
-klausul og du er klar.
Spørgsmålet er, hvordan du refererer til de involverede tabeller? Det skal du bruge Arel til. Du kunne brug Arels where
med sine grimme forhold som a.eq b
. Men hvorfor? Da det er en ligestillingsbetingelse, kan du bruge Rails' betingelser i stedet for! Du kan referere til den tabel, du forespørger på med en hash-nøgle, men for den anden tabel (i den ydre forespørgsel) kan du bruge dens arel_table
. Se dette:
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
Du kan endda reducere Arel-forbruget ved at ty til strenge lidt og stole på, at du kan indlæse underforespørgsler som parametre til Rails' where
. Der er ikke meget brug for det, men det tvinger dig ikke til at grave for meget i Arels metoder, så du kan bruge det trick eller andre SQL-operatorer, der tager en underforespørgsel (er der overhovedet andre?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
De to hovedpunkter her er:
- Du kan bygge underforespørgsler på samme måde, som du er vant til at bygge almindelige forespørgsler, ved at referere til den ydre forespørgsels tabel med Arel. Det er måske ikke engang et rigtigt bord, det kan være et alias! Skøre ting.
- Du kan bruge underforespørgsler som parametre for Rails'
where
metode helt fint.