I am trying to build a scope in my rails model that, when invoked, would give me a set of nested AND and OR clauses on 7 boolean fields. Here's an example with simplified column names for clarity:
SELECT * FROM mytable
WHERE (a AND b AND c) OR (a AND d AND e) OR (a AND f AND g);
Note that column a
is present in all three clauses. Another way to write it would be:
SELECT * FROM mytable
WHERE a AND ((b AND c) OR (d AND e) OR (f AND g));
Arel seems less forgiving on the second form. I've gotten really close with the follwing scope:
scope :needs_any_delivery, lambda {
table = self.arel_table
common_assert = table[:a].eq(true)
where(
common_assert.and(
table[:b].eq(true).and(
table[:c].eq(false)
)
).or(
common_assert.and(
table[:d].eq(true).and(
table[:e].eq(false)
)
).or(
common_assert.and(
table[:f].eq(true).and(
table[:g].eq(false)
)
)
)
)
)
}
This produces the following query:
SELECT * FROM mytable
WHERE (
(a = 't' AND b = 't' AND c = 'f'
OR (a = 't' AND d = 't' AND e = 'f' OR a = 't' AND f = 't' AND g = 'f')
)
)
It's close, but the third AND
group is not being separated from the second AND
group. I've found that if I put some additional bogus or
clause onto the end of the third group then Arel appropriately groups the third clause on its own... but that seems like a hack.
Wondering if any rails/arel gurus out there have any ideas. Thanks!