---
title: Finding the opposite of what you have with rails invert_where
teaser: Need to fetch the opposite data for an existing ActiveRecord query? Rails
  invert_where makes it effortless, but be careful with the side effects.
tags: activerecord,ruby,rails,development
author: Trésor Bireke
published_on: 2025-03-14
---

Rails 7 introduced `invert_where`. This method inverts all scope conditions that it's applied to, simplifying the process of defining the opposite of a `where` clause in ActiveRecord queries. It also comes with a few caveats that should be considered before using it.

## What is `invert_where`?

`invert_where` is a Rails method that can fetch all the data that is excluded by an existing query.

Let's take this example: finding recent claims that have been raised on completed orders and have an amount of less than £100.

```ruby
recent_claims = Claim.joins(:order)
				.where(orders: { status: "completed" })
                .where("claims.created_at >= ?", 10.days.ago)
                .where("claims.claim_amount < ?", 100)
```

If you want to query data opposite to the query condition, you would need to write the opposite query like:

```ruby
claims = Claim.joins(:order)
old_claims = claims.where.not(orders: { status: "completed" })
                   .or(claims.where("claims.created_at < ?", 10.days.ago))
                   .or(claims.where("claims.claim_amount >= ?", 100))
```

Using `invert_where` the opposite condition becomes as simple as

```ruby
old_claims = recent_claims.invert_where
```

## `invert_where` Gotcha

Using `invert_where` in models with default scopes can lead to unintended inversions. For instance:

```ruby
class Claim < ApplicationRecord
  default_scope { where(archived: false) }
  scope :recent, -> { where("created_at >= ?", 10.days.ago) }
end

# Inverted scope
old_claims = Claim.recent.invert_where
```

In the above example, `invert_where` will invert both the recent scope and the `default_scope`, potentially returning archived claims, which is most likely not the desired result.

## Conclusion

**Prefer Using Explicit Conditions**: Consider explicitly defining the inverse conditions using where.not instead of `inverse_where`. This approach provides more clarity and control over the query’s behavior.

**Isolate Inversions**: If you choose to use `invert_where`, apply it to isolated scopes or conditions to minimize unintended inversions.

**Be Cautious with Default Scopes**: Avoid using `invert_where` in models with default scopes, or ensure that the default scope’s inversion aligns with your intended query results.

**Unit test Inverted scopes**: Since `invert_where` inverts all conditions in a scope, it's important to validate that the new scope behaves as expected with tests; that becomes more crucial when you have default scopes or complex queries.
