Usando arel
può portarti abbastanza lontano. La parte difficile è come non scrivere l'intera query utilizzando arel
sintassi della query personale?
Ecco un trucco:quando crei la tua query usando where
, se usi arel
condizioni, ottieni alcuni metodi extra gratuitamente. Ad esempio, puoi pedinare la sottoquery che hai lì con .exists.not
, che ti darà un (NOT ( EXISTS (subquery)))
Gettalo nel where
del genitore -clausola e sei a posto.
La domanda è:come si fa a fare riferimento alle tabelle coinvolte? Hai bisogno di Arel per quello. Potresti usa where
di Arel con le sue brutte condizioni come a.eq b
. Ma perché? Poiché è una condizione di uguaglianza, puoi invece utilizzare le condizioni di Rails! Puoi fare riferimento alla tabella che stai interrogando con una chiave hash, ma per l'altra tabella (nella query esterna) puoi usare la sua arel_table
. Guarda questo:
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
Puoi anche ridurre l'utilizzo di Arel ricorrendo un po' alle stringhe e basandoti sul fatto che puoi inserire sottoquery come parametri per where
di Rails . Non è molto utile, ma non ti costringe a scavare troppo nei metodi di Arel, quindi puoi usare quel trucco o altri operatori SQL che accettano una sottoquery (ce ne sono anche altri?):
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
I due punti principali qui sono:
- Puoi creare sottoquery nello stesso modo in cui sei abituato a creare query regolari, facendo riferimento alla tabella della query esterna con Arel. Potrebbe non essere nemmeno un vero tavolo, potrebbe essere uno pseudonimo! Roba da pazzi.
- Puoi usare le sottoquery come parametri per
where
di Rails metodo bene.