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
wheredo Rails método muito bem.