Posted about 1 month ago. Visible to the public. Repeats.

How to negate scope conditions in Rails

Rails does not offer a "vanilla" way of negating an ActiveRecord scope. Here are two ways to do it yourself without too much effort.

Example:

Copy
class User scope :admins, -> { where(role: ['admin', 'superuser'] } # ... end

Now what if we want a scope of users that are not admins? While you could declare a second scope like scope :non_admins, -> { where(role: ['guest', 'editor']) }, there are ways to use the opposite of the admins scope.

Option A: Subquery

You could just use a subquery. Doing that with scopes is easy:

Copy
User.where.not(id: User.admins)

Rails will generate a query like the following.

Copy
SELECT * FROM users WHERE id NOT IN (SELECT id FROM users WHERE role IN ('admin', 'superuser'))

Note that subqueries may be inefficient on large tables.

Option B: Use where_values_hash

You may use where_values_hash from ActiveRecord::Relation to construct a single SQL query which NOTs your scope's conditions.

Copy
User.where.not(User.admins.where_values_hash)

That's just like saying User.where.not(role: ['admin', 'superuser']), but programmatically.

The resulting SQL is quite pretty.

Copy
SELECT * FROM users WHERE role NOT IN ('admin', 'superuser')

This will not work for scopes using joins or similar, as where_values_hash does not include those. While there is probably a way to do it, I suggest just using a subquery in such cases.

Note that - as always in SQL - this query will not return rows where role is "NULL", since in SQL "NOT NULL = NULL".

Once an application no longer requires constant development, it needs periodic maintenance for stable and secure operation. makandra offers monthly maintenance contracts that let you focus on your business while we make sure the lights stay on.

Owner of this card:

Avatar
Arne Hartherz
Last edit:
about 1 month ago
by Tobias Kraze
About this deck:
We are makandra and do test-driven, agile Ruby on Rails software development.
License for source code
Posted by Arne Hartherz to makandra dev
This website uses short-lived cookies to improve usability.
Accept or learn more