Using arel can lead you to pretty far. The hard part is, how do you not write your entire query using arel own query syntax?
Here's the trick: when creating a query using where , if you use arel conditions, you get free additional methods. For example, you can .exists.not subquery that you have there with .exists.not , which will give you (NOT ( EXISTS (subquery))) Toss, which is in parent where -clause, and you will set.
The question is, how do you reference linked tables? For this you need Arel. You could use Arel where with its ugly conditions like a.eq b . But why? Since this is an equality condition, you can use Rails conditions instead! You can reference the table you are querying with a hash key, but for another table (in an external query) you can use its arel_table . See this:
parents = Parent.arel_table Parent.where( Child.where(other_parent_id: nil, parent_id: parents[:id]).exists.not )
You can even reduce the use of Arel by resorting to strings a bit and relying on the fact that you can submit subqueries as parameters of Rails' where . It is not so much, but it does not make you delve into Arel methods too often, so you can use this trick or other SQL statements that accept a subquery (are there even others?):
parents = Parent.arel_table Parent.where('NOT EXISTS (?)', Child.where(parent_id: parents[:id], other_parent_id: nil) )
Here are two key points:
- You can create subqueries just like you are used to building regular queries by referencing an external query table using Arel. Perhaps this is not even a real table, it could be an alias! Crazy stuff.
- You can use subqueries as parameters for the Rails'
where method is just fine.
source share