Rails 7.0 has introduced two methods
find_sole_by that are used to query the database for a unique record based on the provided constraints.
Assertions are one of the most useful tools in Ruby, and they’re even more useful when you use them to test your application’s data. By asserting that the data you got back from an object or collection is what you expect, you can ensure that your code works as expected.
For example, if you have a table that contains data on films and their casts, you may want to assert that the cast for a film exists.
This feature can be used in several ways:
To verify that the result of calling a model method is an instance of your expected class
To verify that the result of calling a model method returns true for your desired attribute name and value pair
To verify that a query returns at least one result
Here it is before Rails 7.0
Suppose we want to find a product with said price
price and it only has to be one:
1 2 3 4 5 6 7 8 9 product = Product.where(price: price).count if product.count == 1 puts product.first elsif product.count == 0 puts "No products found" else puts "More than one product found" end
The complexity with implementations such as above increases especially when we’ll need to query between multiple models to get our result.
Here it is after Rails 7.0
find_sole_by method is similar in function to
find_by, the only difference is that it asserts that the record being retrieved is the only one that exists. From the previous method, we can have a reduced form as below:
1 2 3 4 5 6 product = Product.find_sole_by(price: price) # => ActiveRecord::RecordNotFound (if no matching Product with the price provided) # => #<Product ...> (if one Product with the price provided) # => ActiveRecord::SoleRecordExceeded (if more than one Product with the price provided)
For the method
sole, its functionality is similar to
first, however, it only extracts the results when it’s the only unique one matching the constraints provided.
1 2 3 4 5 6 product = Product.where(price: price).sole # => ActiveRecord::RecordNotFound (if no matching Product with the price provided) # => #<Product ...> (if one Product with the price provided) # => ActiveRecord::SoleRecordExceeded (if more than one Product with the price provided)
So, it takes an options hash that can be used to specify which fields are required and whether or not they should be present in the result.
This method also takes advantage of ActiveCast—a feature introduced in Rails 5 that allows you to access attributes on related models without loading them into memory at all times (which could cause performance issues).
More on this can be read here.