Rails 6.1
added
two query options, namely #sole
and #find_sole_by
to the ActiveRecord::FinderMethods
.
These methods assert that only one unique record is returned from the database.
In Rails 7,
Enumerable#sole
was
added
to the Enumerable
module which behaves similar to
ActiveRecord::FinderMethods
methods - #sole
and #find_sole_by
.
Before
Let’s say we have an app where User
can have multiple api_keys
associated with their accounts.
Each api_key
will be associated with a particular type
.
To implement the above scenario we will design our User and ApiKey models as shown below:
# app/models/user.rb
class User < ApplicationRecord
has_many :api_keys
end
# app/models/api_key.rb
class ApiKey < ApplicationRecord
belongs_to :user
scope :github, -> { where(key_type: "github") }
# == Schema Information
#
# Table name: api_keys
#
# key :string(255)
# user_id :integer
# key_type :string(255)
end
To verify if a user has only one API key of a particular type, we might implement the following code:
user = User.find(1)
keys = user.api_keys.github.pluck(:key)
if keys.length == 1
key = keys.first
elsif keys.length == 0
raise "No records found!"
else
raise "More than one matching record found!"
end
As seen, we have to write a lot of code to fetch a user API key of a particular type.
After
In Rails 7, with Enumerable#sole
we can replace the above code as shown below:
key = user.api_keys.github.pluck(:key).sole
=> "github key"
The Enumerable#sole
method returns one
and
only one element
and
raises an error if there are none or more than one element present in the Enumerable.
key = user.api_keys.github.pluck(:key).sole
# if no API key of particular type exists
=> Enumerable::SoleItemExpectedError (no item found)
# if multiple API keys of a particular type exist
=> Enumerable::SoleItemExpectedError (multiple items found)