Utiliser arel
peut vous mener assez loin. La partie délicate est de savoir comment ne pas écrire toute votre requête en utilisant arel
la propre syntaxe de requête ?
Voici une astuce :lorsque vous créez votre requête en utilisant where
, si vous utilisez arel
conditions, vous obtenez des méthodes supplémentaires gratuitement. Par exemple, vous pouvez suivre la sous-requête que vous avez avec .exists.not
, qui vous donnera un (NOT ( EXISTS (subquery)))
Mettez ça dans le where
du parent -clause et vous êtes prêt.
La question est, comment référencez-vous les tables concernées ? Vous avez besoin d'Arel pour cela. Vous pourriez utiliser le where
d'Arel avec ses vilaines conditions comme a.eq b
. Mais pourquoi? Puisqu'il s'agit d'une condition d'égalité, vous pouvez utiliser les conditions de Rails à la place ! Vous pouvez référencer la table que vous interrogez avec une clé de hachage, mais pour l'autre table (dans la requête externe), vous pouvez utiliser son arel_table
. Regarde ça :
parents = Parent.arel_table
Parent.where(
Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not
)
Vous pouvez même réduire l'utilisation d'Arel en recourant un peu aux chaînes et en vous appuyant sur le fait que vous pouvez alimenter des sous-requêtes en tant que paramètres de where
de Rails. . Cela ne sert pas à grand chose, mais cela ne vous oblige pas à trop creuser dans les méthodes d'Arel, vous pouvez donc utiliser cette astuce ou d'autres opérateurs SQL qui prennent une sous-requête (y en a-t-il même d'autres ?) :
parents = Parent.arel_table
Parent.where('NOT EXISTS (?)',
Child.where(parent_id: parents[:id], other_parent_id: nil)
)
Les deux points principaux ici sont :
- Vous pouvez créer des sous-requêtes de la même manière que vous avez l'habitude de créer des requêtes régulières, en référençant la table de la requête externe avec Arel. Ce n'est peut-être même pas une vraie table, c'est peut-être un alias ! Des trucs dingues.
- Vous pouvez utiliser des sous-requêtes comme paramètres pour
where
de Rails méthode très bien.