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.
info@scriptday.com