Rails 7.0 Added Sole Finder Methods

May 23, 2021

Rails has several finder methods like find, find_by, last, first, etc. in ActiveRecord to query the database to find a single record.

Let's understand how we use find_by or first methods with the help of an example.

If we are asked to update a product name whose price is $1000 and we assume there could be one such product in our products table.

We can update the product name using a find_by as below :

Product.find_by(price: 1000).update(name: name + ' Pro') #or Product.where(price: 1000).first.update(name: name + ' Pro')

The above query will execute and update a record in database.

But the above query did not ensure that there was a single product with price $1000.

Suppose that table had a duplicate entry as follows :

Product.create(name: 'iPhone11 Pro', price: 1000) Product.create(name: 'iPhone12', price: 1000)

Now, this is a genuine problem which can be solved as below :

class MultipleItemsFoundError < StandardError end products = Product.where(price: 1000) if products.size == 1 products.first.update(name: name + ' Pro') else raise MultipleItemsFoundError end

In the above example, we are raising an error MultipleItemsFoundError if the database has multiple records with price $1000.

This is absolutely fine because we assumed there could be a single product with price $1000
and if there is an exception to this then we should raise an error.

Rails 7.0 has added two new methods find_sole_by and sole to ActiveRecord with this pull request
which will help us to address the above problem in much simpler way.

We can rewrite the above code as follows :

Product.find_sole_by(price: 1000).update(name: name + ' Pro') #or Product.where(price: 1000).sole.update(name: name + ' Pro') #=> ActiveRecord::SoleRecordExceeded (Wanted only one Product)

The above code raises an error ActiveRecord::SoleRecordExceeded (Wanted only one Product)
which ensures us that products table has more than one record with price $1000.

This query would have worked if we had only one product with price $1000.

ActiveSupport added Enumerable#sole

Rails has been adding useful methods to ActiveSupport to ease developers job.

While we are waiting for Ruby to introduce a method like sole, Rails 7.0 has added Enumerable#sole with this pull request.

Let's try this out with an example :

mobile_devices = ['iPhone 11', 'iPhone12'] mobile_devices.sole #=> Enumerable::SoleItemExpectedError (multiple items found) mobile_devices = ['iPhone12'] mobile_devices.sole #=> "iPhone12"

As we have seen find_sole_by in action, Enumerable#sole is no different.

It ensures us that there is only one item in the mobile_devices array and returns the single value in it.

Share feedback with us at:


© All rights reserved 2022