Rails 6.1 adds invert_where method

Chimed Palden

By Chimed Palden

on May 4, 2021

This blog is part of our  Rails 6.1 series.

Rails 6.1 adds an invert_where method that will invert all scope conditions.

Let's see an example.

1class User
2  scope :active, -> { where(accepted: true, locked: false) }
3end
4
5>> User.all
6=> #<ActiveRecord::Relation [
7#<User id: 1, name: 'Rob', accepted: true, locked: true>
8#<User id: 2, name: 'Jack', accepted: false, locked: false>
9#<User id: 3, name: 'Nina', accepted: true, locked: false>
10#<User id: 4, name: 'Oliver', accepted: false, locked: true>

Now let's query for active and inactive users

1>> User.active
2# SELECT * FROM Users WHERE `accepted` = 1 AND `locked` = 0
3=> #<ActiveRecord::Relation [
4#<User id: 3, name: 'Nina', accepted: true, locked: false>]>
5
6>> User.active.invert_where
7# SELECT * FROM Users WHERE NOT (`accepted` = 1 AND `locked` = 0)
8=> #<ActiveRecord::Relation [
9#<User id: 1, name: 'Rob', accepted: true, locked: true>
10#<User id: 2, name: 'Jack', accepted: false, locked: false>
11#<User id: 4, name: 'Oliver', accepted: false, locked: true>]>

As we can see above, if we use invert_where with multiple attributes, it applies logical NOR, which is NOT a OR NOT b, to the WHERE clause of the query. Using DeMorgan's Law, it can also be written as NOT (a AND b) to match the second output.

Check out the pull request for more details.

Stay up to date with our blogs. Sign up for our newsletter.

We write about Ruby on Rails, ReactJS, React Native, remote work,open source, engineering & design.