Skip to content

Provides the convenience method `ActiveRecord::Relation#one!`

Notifications You must be signed in to change notification settings

elebow/activerecord-one

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

11 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

activerecord-one

Provides ActiveRecord::Relation#one!, a convenience method that asserts a relation contains exactly one record and returns it. If there are no records or more than one, an ActiveRecord::NoRecordFound or ActiveRecord::MultipleRecordsFound exception is raised, respectively.

#one! reads as follows:

def one!
  case size
  when 0
    raise ActiveRecord::NoRecordFound
  when 1
    first
  else
    raise ActiveRecord::MultipleRecordsFound
  end
end

Why not use find_by?

find_by doesn't verify uniqueness. The Rails documentation for the method says:

Finds the first record matching the specified conditions. There is no implied ordering so if order matters, you should specify it yourself.

Therefore, given the following records:

#<Record id: 1, name: "Alice", color: "red">,
#<Record id: 2, name: "Bob", color: "blue">,
#<Record id: 3, name: "Bob", color: "green">

The following expression has undefined behavior:

Record.find_by(name: "Bob")    # could return record 2 or record 3!

The record returned is whatever the database decides is first. There's no way to tell from the code alone which it will be, or that such a thing has even happened. In other words, find_by is only safe when you specify the order of rows, or have confidence that no more than one row will match—usually thanks to a uniqueness constraint in the database.

If you expect only one row to match but don't have a database uniqueness constraint (perhaps due to non-unique legacy data, for example), you would need to do something like:

raise unless Record.where(name: "Bob").count == 1
Record.find_by(name: "Bob")

Or, with this gem:

Record.where(name: "Bob").one!

Shouldn't this be provided by Rails?

Probably. See rails/rails#26206.

Installation

Add this line to your application's Gemfile:

gem 'activerecord-one'

And then execute:

$ bundle

Or install it yourself as:

$ gem install activerecord-one

License

This gem is dedicated to the public domain. In jurisdictions where this is not possible, this gem is licensed to all under the least restrictive terms possible, and all copyright rights are waived.

About

Provides the convenience method `ActiveRecord::Relation#one!`

Resources

Stars

Watchers

Forks

Packages

No packages published

Languages