Usando
arel
pode levá-lo muito longe. A parte complicada é como você não escreve sua consulta inteira usando arel
própria sintaxe de consulta? Aqui está um truque:ao construir sua consulta usando
where
, se você usar arel
condições, você obtém alguns métodos extras gratuitamente. Por exemplo, você pode seguir a subconsulta com .exists.not
, que lhe dará um (NOT ( EXISTS (subquery)))
Jogue isso no where
dos pais -cláusula e você está pronto. A questão é:como você faz referência às tabelas envolvidas? Você precisa de Arel para isso. Você poderia use o
where
do Arel com suas condições feias como a.eq b
. Mas por que? Como é uma condição de igualdade, você pode usar as condições do Rails! Você pode fazer referência à tabela que está consultando com uma chave de hash, mas para a outra tabela (na consulta externa) você pode usar sua arel_table
. Vê isto:parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
Você pode até reduzir o uso do Arel recorrendo um pouco a strings e contando com o fato de poder alimentar subconsultas como parâmetros para
where
do Rails . Não há muito uso para isso, mas não força você a se aprofundar muito nos métodos de Arel, então você pode usar esse truque ou outros operadores SQL que fazem uma subconsulta (existem outros?):parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
Os dois pontos principais aqui são:
- Você pode construir subconsultas da mesma forma que está acostumado a construir consultas regulares, referenciando a tabela da consulta externa com Arel. Pode até não ser uma mesa real, pode ser um pseudônimo! Coisas loucas.
- Você pode usar subconsultas como parâmetros para
where
do Rails método muito bem.