Repository: rails/rails
File: activerecord/lib/active_record/relation/finder_methods.rb (Ruby)

Code before:
    # Find the first record (or first N records if a parameter is supplied).
    # If no order is defined it will order by primary key.
    #
    #   Person.first # returns the first object fetched by SELECT * FROM people ORDER BY people.id LIMIT 1
    #   Person.where(["user_name = ?", user_name]).first
    #   Person.where(["user_name = :u", { u: user_name }]).first
    #   Person.order("created_on DESC").offset(5).first
    #   Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
    #
    def first(limit = nil)
      check_reorder_deprecation unless loaded?

      if limit
        find_nth_with_limit(0, limit)
      else
        find_nth 0
      end
    end

    # Same as #first but raises ActiveRecord::RecordNotFound if no record
    # is found. Note that #first! accepts no arguments.
    def first!
      first || raise_record_not_found_exception!
    end

    # Find the last record (or last N records if a parameter is supplied).
    # If no order is defined it will order by primary key.
    #
    #   Person.last # returns the last object fetched by SELECT * FROM people
    #   Person.where(["user_name = ?", user_name]).last
    #   Person.order("created_on DESC").offset(5).last
    #   Person.last(3) # returns the last three objects fetched by SELECT * FROM people.
    #
    # Take note that in that last case, the results are sorted in ascending order:
    #
    #   [#<Person id:2>, #<Person id:3>, #<Person id:4>]
    #
    # and not:
    #
    #   [#<Person id:4>, #<Person id:3>, #<Person id:2>]
    def last(limit = nil)
      return find_last(limit) if loaded? || has_limit_or_offset?

      result = ordered_relation.limit(limit)
      result = result.reverse_order!

      limit ? result.reverse : result.first
    end

    # Same as #last but raises ActiveRecord::RecordNotFound if no record
    # is found. Note that #last! accepts no arguments.

Review comment (suggestion):
Feels like we'd be doing a fair amount of queries here, and we could try sidestepping that by loading 2 records. This should be fine since the second record should pretty much always be nil in the base case.

```suggestion
def only!
  found, undesired = first(2)
  raise_record_not_found_exception! if found.nil?

  if undesired
    error = +"Wanted only one #{name}"
    conditions = " [#{arel.where_sql(klass)}]" unless where_clause.empty?
    error << " with#{conditions}" if conditions
    raise ActiveRecord::MultipleRecordsFound.new(error, name, primary_key)
  end

  found
end
```

Code after:
    # Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
    # record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
    # record is found.
    #
    #   Product.where(["price = %?", price]).sole
    def sole
      found, undesired = first(2)

      case
      when found.nil?
        raise_record_not_found_exception!
      when undesired.present?
        raise ActiveRecord::SoleRecordExceeded.new(self)
      else
        found
      end
    end

    # Finds the sole matching record. Raises ActiveRecord::RecordNotFound if no
    # record is found. Raises ActiveRecord::SoleRecordExceeded if more than one
    # record is found.
    #
    #   Product.find_sole_by(["price = %?", price])
    def find_sole_by(arg, *args)
      where(arg, *args).sole
    end

    # Find the first record (or first N records if a parameter is supplied).
    # If no order is defined it will order by primary key.
    #
    #   Person.first # returns the first object fetched by SELECT * FROM people ORDER BY people.id LIMIT 1
    #   Person.where(["user_name = ?", user_name]).first
    #   Person.where(["user_name = :u", { u: user_name }]).first
    #   Person.order("created_on DESC").offset(5).first
    #   Person.first(3) # returns the first three objects fetched by SELECT * FROM people ORDER BY people.id LIMIT 3
    #
    def first(limit = nil)
      check_reorder_deprecation unless loaded?

      if limit
        find_nth_with_limit(0, limit)
      else
        find_nth 0
      end
    end

    # Same as #first but raises ActiveRecord::RecordNotFound if no record
    # is found. Note that #first! accepts no arguments.
    def first!
      first || raise_record_not_found_exception!
    end