module ActiveRecord::FinderMethods - activerecord-4.2.5.2 Documentation

# module ActiveRecord::FinderMethods

### Constants

ONE_AS_ONE

### Public Instance Methods

exists?(conditions = :none) click to toggle source

Returns `true` if a record exists in the table that matches the `id` or conditions given, or `false` otherwise. The argument can take six forms:

- Integer - Finds the record with this primary key.

- String - Finds the record with a primary key corresponding to this string (such as `'5'`).

- Array - Finds the record that matches these `find`-style conditions (such as `['name LIKE ?', "%#{query}%"]`).

- Hash - Finds the record that matches these `find`-style conditions (such as `{name: 'David'}`).

- `false` - Returns always `false`.

- No args - Returns `false` if the table is empty, `true` otherwise.

For more information about specifying conditions as a hash or array, see the Conditions section in the introduction to `ActiveRecord::Base`.

Note: You can't pass in a condition as a string (like `name = 'Jamie'`), since it would be sanitized and then queried against the primary key column, like `id = 'name = \'Jamie\''`.

    Person.exists?(5)
    Person.exists?('5')
    Person.exists?(['name LIKE ?', "%#{query}%"])
    Person.exists?(id: [1, 4, 8])
    Person.exists?(name: 'David')
    Person.exists?(false)
    Person.exists?

    # File lib/active_record/relation/finder_methods.rb, line 277
        def exists?(conditions = :none)
          if Base === conditions
            conditions = conditions.id
            ActiveSupport::Deprecation.warn("          You are passing an instance of ActiveRecord::Base to `exists?`.
              Please pass the id of the object by calling `.id`
    ".squish)
          end

          return false if !conditions

          relation = apply_join_dependency(self, construct_join_dependency)
          return false if ActiveRecord::NullRelation === relation

          relation = relation.except(:select, :order).select(ONE_AS_ONE).limit(1)

          case conditions
          when Array, Hash
            relation = relation.where(conditions)
          else
            unless conditions == :none
              relation = relation.where(primary_key => conditions)
            end
          end

          connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false
        end

fifth() click to toggle source

Find the fifth record. If no order is defined it will order by primary key.

    Person.fifth # returns the fifth object fetched by SELECT * FROM people
    Person.offset(3).fifth # returns the fifth object from OFFSET 3 (which is OFFSET 7)
    Person.where(["user_name = :u", { u: user_name }]).fifth

    # File lib/active_record/relation/finder_methods.rb, line 224
    def fifth
      find_nth(4, offset_index)
    end

fifth!() click to toggle source

Same as `fifth` but raises `ActiveRecord::RecordNotFound` if no record is found.

    # File lib/active_record/relation/finder_methods.rb, line 230
    def fifth!
      find_nth! 4
    end

find(*args) { |*block_args| ... } click to toggle source

Find by id - This can either be a specific id (1), a list of ids (1, 5, 6), or an array of ids ([5, 6, 10]). If no record can be found for all of the listed ids, then RecordNotFound will be raised. If the primary key is an integer, find by id coerces its arguments using `to_i`.

    Person.find(1)          # returns the object for ID = 1
    Person.find("1")        # returns the object for ID = 1
    Person.find("31-sarah") # returns the object for ID = 31
    Person.find(1, 2, 6)    # returns an array for objects with IDs in (1, 2, 6)
    Person.find([7, 17])    # returns an array for objects with IDs in (7, 17)
    Person.find([1])        # returns an array for the object with ID = 1
    Person.where("administrator = 1").order("created_on DESC").find(1)

`ActiveRecord::RecordNotFound` will be raised if one or more ids are not found.

NOTE: The returned records may not be in the same order as the ids you provide since database rows are unordered. You'd need to provide an explicit `order` option if you want the results are sorted.

#### Find with lock¶ ↑

Example for find with a lock: Imagine two concurrent transactions: each will read `person.visits == 2`, add 1 to it, and save, resulting in two saves of `person.visits = 3`. By locking the row, the second transaction has to wait until the first is finished; we get the expected `person.visits == 4`.

    Person.transaction do
      person = Person.lock(true).find(1)
      person.visits += 1
      person.save!
    end

#### Variations of `find`¶ ↑

    Person.where(name: 'Spartacus', rating: 4)
    # returns a chainable list (which can be empty).

    Person.find_by(name: 'Spartacus', rating: 4)
    # returns the first item or nil.

    Person.where(name: 'Spartacus', rating: 4).first_or_initialize
    # returns the first item or returns a new instance (requires you call .save to persist against the database).

    Person.where(name: 'Spartacus', rating: 4).first_or_create
    # returns the first item or creates it and returns it, available since Rails 3.2.1.

#### Alternatives for `find`¶ ↑

    Person.where(name: 'Spartacus', rating: 4).exists?(conditions = :none)
    # returns a boolean indicating if any record with the given conditions exist.

    Person.where(name: 'Spartacus', rating: 4).select("field1, field2, field3")
    # returns a chainable list of instances with only the mentioned fields.

    Person.where(name: 'Spartacus', rating: 4).ids
    # returns an Array of ids, available since Rails 3.2.1.

    Person.where(name: 'Spartacus', rating: 4).pluck(:field1, :field2)
    # returns an Array of the required fields, available since Rails 3.1.

    # File lib/active_record/relation/finder_methods.rb, line 67
    def find(*args)
      if block_given?
        to_a.find(*args) { |*block_args| yield(*block_args) }
      else
        find_with_ids(*args)
      end
    end

find_by(*args) click to toggle source

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

If no record is found, returns `nil`.

    Post.find_by name: 'Spartacus', rating: 4
    Post.find_by "published_at < ?", 2.weeks.ago

    # File lib/active_record/relation/finder_methods.rb, line 83
    def find_by(*args)
      where(*args).take
    rescue RangeError
      nil
    end

find_by!(*args) click to toggle source

Like `find_by`, except that if no record is found, raises an `ActiveRecord::RecordNotFound` error.

    # File lib/active_record/relation/finder_methods.rb, line 91
    def find_by!(*args)
      where(*args).take!
    rescue RangeError
      raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value"
    end

first(limit = nil) click to toggle source

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

    # File lib/active_record/relation/finder_methods.rb, line 123
    def first(limit = nil)
      if limit
        find_nth_with_limit(offset_index, limit)
      else
        find_nth(0, offset_index)
      end
    end

first!() click to toggle source

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

    # File lib/active_record/relation/finder_methods.rb, line 133
    def first!
      find_nth! 0
    end

forty_two() click to toggle source

Find the forty-second record. Also known as accessing “the reddit”. If no order is defined it will order by primary key.

    Person.forty_two # returns the forty-second object fetched by SELECT * FROM people
    Person.offset(3).forty_two # returns the forty-second object from OFFSET 3 (which is OFFSET 44)
    Person.where(["user_name = :u", { u: user_name }]).forty_two

    # File lib/active_record/relation/finder_methods.rb, line 240
    def forty_two
      find_nth(41, offset_index)
    end

forty_two!() click to toggle source

Same as `forty_two` but raises `ActiveRecord::RecordNotFound` if no record is found.

    # File lib/active_record/relation/finder_methods.rb, line 246
    def forty_two!
      find_nth! 41
    end

fourth() click to toggle source

Find the fourth record. If no order is defined it will order by primary key.

    Person.fourth # returns the fourth object fetched by SELECT * FROM people
    Person.offset(3).fourth # returns the fourth object from OFFSET 3 (which is OFFSET 6)
    Person.where(["user_name = :u", { u: user_name }]).fourth

    # File lib/active_record/relation/finder_methods.rb, line 208
    def fourth
      find_nth(3, offset_index)
    end

fourth!() click to toggle source

Same as `fourth` but raises `ActiveRecord::RecordNotFound` if no record is found.

    # File lib/active_record/relation/finder_methods.rb, line 214
    def fourth!
      find_nth! 3
    end

last(limit = nil) click to toggle source

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>]

    # File lib/active_record/relation/finder_methods.rb, line 152
    def last(limit = nil)
      if limit
        if order_values.empty? && primary_key
          order(arel_table[primary_key].desc).limit(limit).reverse
        else
          to_a.last(limit)
        end
      else
        find_last
      end
    end

last!() click to toggle source

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

    # File lib/active_record/relation/finder_methods.rb, line 166
    def last!
      last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
    end

second() click to toggle source

Find the second record. If no order is defined it will order by primary key.

    Person.second # returns the second object fetched by SELECT * FROM people
    Person.offset(3).second # returns the second object from OFFSET 3 (which is OFFSET 4)
    Person.where(["user_name = :u", { u: user_name }]).second

    # File lib/active_record/relation/finder_methods.rb, line 176
    def second
      find_nth(1, offset_index)
    end

second!() click to toggle source

Same as `second` but raises `ActiveRecord::RecordNotFound` if no record is found.

    # File lib/active_record/relation/finder_methods.rb, line 182
    def second!
      find_nth! 1
    end

take(limit = nil) click to toggle source

Gives a record (or N records if a parameter is supplied) without any implied order. The order will depend on the database implementation. If an order is supplied it will be respected.

    Person.take # returns an object fetched by SELECT * FROM people LIMIT 1
    Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
    Person.where(["name LIKE '%?'", name]).take

    # File lib/active_record/relation/finder_methods.rb, line 104
    def take(limit = nil)
      limit ? limit(limit).to_a : find_take
    end

take!() click to toggle source

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

    # File lib/active_record/relation/finder_methods.rb, line 110
    def take!
      take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
    end

third() click to toggle source

Find the third record. If no order is defined it will order by primary key.

    Person.third # returns the third object fetched by SELECT * FROM people
    Person.offset(3).third # returns the third object from OFFSET 3 (which is OFFSET 5)
    Person.where(["user_name = :u", { u: user_name }]).third

    # File lib/active_record/relation/finder_methods.rb, line 192
    def third
      find_nth(2, offset_index)
    end

third!() click to toggle source

Same as `third` but raises `ActiveRecord::RecordNotFound` if no record is found.

    # File lib/active_record/relation/finder_methods.rb, line 198
    def third!
      find_nth! 2
    end

### Protected Instance Methods

find_last() click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 503
    def find_last
      if loaded?
        @records.last
      else
        @last ||=
          if limit_value
            to_a.last
          else
            reverse_order.limit(1).to_a.first
          end
      end
    end

find_nth(index, offset) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 479
    def find_nth(index, offset)
      if loaded?
        @records[index]
      else
        offset += index
        @offsets[offset] ||= find_nth_with_limit(offset, 1).first
      end
    end

find_nth!(index) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 488
    def find_nth!(index)
      find_nth(index, offset_index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql}]")
    end

find_nth_with_limit(offset, limit) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 492
    def find_nth_with_limit(offset, limit)
      relation = if order_values.empty? && primary_key
                   order(arel_table[primary_key].asc)
                 else
                   self
                 end

      relation = relation.offset(offset) unless offset.zero?
      relation.limit(limit).to_a
    end

find_one(id) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 432
        def find_one(id)
          if ActiveRecord::Base === id
            id = id.id
            ActiveSupport::Deprecation.warn("          You are passing an instance of ActiveRecord::Base to `find`.
              Please pass the id of the object by calling `.id`
    ".squish)
          end

          relation = where(primary_key => id)
          record = relation.take

          raise_record_not_found_exception!(id, 0, 1) unless record

          record
        end

find_some(ids) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 449
    def find_some(ids)
      result = where(primary_key => ids).to_a

      expected_size =
        if limit_value && ids.size > limit_value
          limit_value
        else
          ids.size
        end

      # 11 ids with limit 3, offset 9 should give 2 results.
      if offset_value && (ids.size - offset_value < expected_size)
        expected_size = ids.size - offset_value
      end

      if result.size == expected_size
        result
      else
        raise_record_not_found_exception!(ids, result.size, expected_size)
      end
    end

find_take() click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 471
    def find_take
      if loaded?
        @records.first
      else
        @take ||= limit(1).to_a.first
      end
    end

find_with_ids(*ids) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 411
    def find_with_ids(*ids)
      raise UnknownPrimaryKey.new(@klass) if primary_key.nil?

      expects_array = ids.first.kind_of?(Array)
      return ids.first if expects_array && ids.first.empty?

      ids = ids.flatten.compact.uniq

      case ids.size
      when 0
        raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
      when 1
        result = find_one(ids.first)
        expects_array ? [ result ] : result
      else
        find_some(ids)
      end
    rescue RangeError
      raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID"
    end

### Private Instance Methods

apply_join_dependency(relation, join_dependency) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 379
    def apply_join_dependency(relation, join_dependency)
      relation = relation.except(:includes, :eager_load, :preload)
      relation = relation.joins join_dependency

      if using_limitable_reflections?(join_dependency.reflections)
        relation
      else
        if relation.limit_value
          limited_ids = limited_ids_for(relation)
          limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids))
        end
        relation.except(:limit, :offset)
      end
    end

construct_join_dependency(joins = []) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 362
    def construct_join_dependency(joins = [])
      including = eager_load_values + includes_values
      ActiveRecord::Associations::JoinDependency.new(@klass, including, joins)
    end

construct_relation_for_association_calculations() click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 367
    def construct_relation_for_association_calculations
      from = arel.froms.first
      if Arel::Table === from
        apply_join_dependency(self, construct_join_dependency(joins_values))
      else
        # FIXME: as far as I can tell, `from` will always be an Arel::Table.
        # There are no tests that test this branch, but presumably it's
        # possible for `from` to be a list?
        apply_join_dependency(self, construct_join_dependency(from))
      end
    end

find_with_associations() { |relation| ... } click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 333
    def find_with_associations
      # NOTE: the JoinDependency constructed here needs to know about
      #       any joins already present in `self`, so pass them in
      #
      # failing to do so means that in cases like activerecord/test/cases/associations/inner_join_association_test.rb:136
      # incorrect SQL is generated. In that case, the join dependency for
      # SpecialCategorizations is constructed without knowledge of the
      # preexisting join in joins_values to categorizations (by way of
      # the `has_many :through` for categories).
      #
      join_dependency = construct_join_dependency(joins_values)

      aliases  = join_dependency.aliases
      relation = select aliases.columns
      relation = apply_join_dependency(relation, join_dependency)

      if block_given?
        yield relation
      else
        if ActiveRecord::NullRelation === relation
          []
        else
          arel = relation.arel
          rows = connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
          join_dependency.instantiate(rows, aliases)
        end
      end
    end

limited_ids_for(relation) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 394
    def limited_ids_for(relation)
      values = @klass.connection.columns_for_distinct(
        "#{quoted_table_name}.#{quoted_primary_key}", relation.order_values)

      relation = relation.except(:select).select(values).distinct!
      arel = relation.arel

      id_rows = @klass.connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values)
      id_rows.map {|row| row[primary_key]}
    end

offset_index() click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 329
    def offset_index
      offset_value || 0
    end

using_limitable_reflections?(reflections) click to toggle source

    # File lib/active_record/relation/finder_methods.rb, line 405
    def using_limitable_reflections?(reflections)
      reflections.none? { |r| r.collection? }
    end