Rails has many finder methods, and most of them are built around a simple idea: return the first matching record, return all matching records, or raise when nothing is found.

find_sole_by is a little stricter. It is useful when your code expects exactly one record to match a condition.

User.find_sole_by(email: "[email protected]")

This query has three possible outcomes:

  • If exactly one user matches, Rails returns that user.
  • If no users match, Rails raises ActiveRecord::RecordNotFound.
  • If more than one user matches, Rails raises ActiveRecord::SoleRecordExceeded.

That last case is what makes find_sole_by interesting.

Why not just use find_by?

find_by returns the first matching record:

User.find_by(email: "[email protected]")

If there are duplicate users with the same email, find_by will quietly return one of them. That may hide a data problem.

find_sole_by refuses to hide it. If the data says there is more than one matching row, Rails raises an error and makes the problem visible.

Where it fits

Use find_sole_by when the query describes something that should be unique:

Account.find_sole_by(subdomain: "acme")
Product.find_sole_by(sku: "TSHIRT-001")
Invitation.find_sole_by(token: params[:token])

It works well in code where returning the wrong record would be worse than raising an exception.

Still add the unique index

find_sole_by is not a replacement for a database constraint. It helps your application notice unexpected duplicates, but it does not prevent duplicates from being created.

If the column should be unique, keep that rule in the database:

add_index :users, :email, unique: true

The database protects the data. find_sole_by protects the assumption in the code.

The short version

Use find_by when any matching record is acceptable.

Use find_sole_by when exactly one matching record must exist, and duplicate matches should be treated as a bug.