Eric Saboia
Eric Saboia

Reputation: 1234

Rewhere or unscope a query containing an array condition on Rails

I'm trying to rewhere or unscope a query, where the original condition cannot be written using hash condition:

Reservation.where('block_id IS NULL OR block_id != ?', 'something')

> SELECT `reservations`.* FROM `reservations` WHERE (block_id IS NULL OR block_id != 'something')

Trying to rewhere doesn't work:

Reservation.where('block_id IS NULL OR block_id != ?', 'something').rewhere(block_id: 'anything')

> SELECT `reservations`.* FROM `reservations` WHERE (block_id IS NULL OR block_id != 'something') AND `reservations`.`block_id` = 'anything'

But this example with hash condition would work:

Reservation.where.not(block_id: 'something').rewhere(block_id: 'anything')

> SELECT `reservations`.* FROM `reservations` WHERE `reservations`.`block_id` = 'anything'

I understand that this is probably because on the array condition rails doesn't know which column I'm invoking a where, and therefore rewhere won't find anything to replace.

Is there any way to explicitly tell which column I'm filtering in an array condition? or rewrite the first query (IS NULL OR != value) with hash condition?

Note: Please don't suggest unscoped, as I'm trying to unscope/rewhere only this specific condition, not the whole query.

Thanks!

Upvotes: 3

Views: 1026

Answers (1)

Marc Rohloff
Marc Rohloff

Reputation: 1352

Sorry it wasn't clear that you had other where clauses that you wanted to keep. You could access the array of where clauses using relations.values[:where] and manipulate it, something like:

Reservation.where('block_id IS NULL OR block_id != ?', 'something')
           .tap do |relation|
                  # Depending on your version of Rails you can do 
                  where_values = relation.where_values
                  # Or
                  where_values = relation.values[:where]
                  # With the first probably being better
                  where_values.delete_if { |where| ... }
                end
           .where(block_id: 'anything')

aka hacking

Upvotes: 3

Related Questions