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

Akanksha Jain

Akanksha Jain

March 2, 2021

This blog is part of our  Rails 7 series.


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.

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:

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:

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 for more details.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.