---
title: "Rails 7.0 adds ActiveRecord::FinderMethods 'sole' and 'find_sole_by"
description:
  "Rails 7.0 adds ActiveRecord::FinderMethods `#sole` and `#find_sole_by`"
canonical_url: "https://www.bigbinary.com/blog/rails-7-adds-active-record-finder-methods"
markdown_url: "https://www.bigbinary.com/blog/rails-7-adds-active-record-finder-methods.md"
---

# Rails 7.0 adds ActiveRecord::FinderMethods 'sole' and 'find_sole_by

Rails 7.0 adds ActiveRecord::FinderMethods `#sole` and `#find_sole_by`

- Author: Akanksha Jain
- Published: March 2, 2021
- Categories: Rails, Rails 7

<br />

### Before Rails 7.0

There were no methods defined to find and assert the presence of exactly one
record at the same time.

For example, we have a class Product with a `price` field and we want to find a
single product that has a price of 100. For zero or multiple products with the
price of 100, we want to raise an error. We can not add database constraints to
make a unique field of `price`.

Now to solve the above query, we don't have any method defined in
`ActiveRecord::FinderMethods` module. We can find a product with the given price
or raise an error if no record is found using the queries mentioned in the below
example.

```ruby
Product.find_by!(price: price)
#=> ActiveRecord::RecordNotFound Exception     (if no Product with the given price)
#=> #<Product ...>                             (first product with the given price)

Product.where(price: price).first!
#=> ActiveRecord::RecordNotFound Exception     (if no Product with the given price)
#=> #<Product ...>                             (first product with the given price)
```

We can only use database constraints to make a field unique and if adding
constraints is impractical then we would have to define our own method.

For example:

```ruby
def self.find_first!(arg, *args)
  products = where(arg, *args)

  case
  when products.empty?
    raise_record_not_found_exception!
  when products.count > 0
    raise 'More than one record present'
  else
    products.first
  end
end

Product.find_first!(price: price)
#=> ActiveRecord::RecordNotFound Exception     (if no Product with the given price)
#=> #<Product ...>                             (if one Product with the given price)
#=> ActiveRecord::SoleRecordExceeded Exception (if more than one Product with the given price)
```

### After Rails 7.0

Rails 7.0 has added `#sole` and `#find_sole_by` methods in the
ActiveRecord::FinderMethods module. These methods are used to find and assert
the presence of exactly one record.

When a user wants to find a single row, but also wants to assert that there
aren't any other rows matching the condition (especially for when the database
constraints aren't enough or are impractical), then these methods come into use.

For example:

```ruby
class Product
    validates :price, presence: true
end

Product.where(["price = %?", price]).sole
#=> ActiveRecord::RecordNotFound Exception     (if no Product with the given price)
#=> #<Product ...>                             (if one Product with the given price)
#=> ActiveRecord::SoleRecordExceeded Exception (if more than one Product with the given price)

Product.find_sole_by(price: price)
#=> ActiveRecord::RecordNotFound Exception     (if no Product with the given price)
#=> #<Product ...>                             (if one Product with the given price)
#=> ActiveRecord::SoleRecordExceeded Exception (if more than one Product with the given price)
```

Check out the [pull request](https://github.com/rails/rails/pull/40768) for more
details.

## Links

- [Human page](https://www.bigbinary.com/blog/rails-7-adds-active-record-finder-methods)
