Methods
A
C
E
F
L
U
Instance Public methods
all(*args)

A convenience wrapper for find(:all, *args). You can pass in all the same arguments to this method as you can to find(:all).

# File activerecord/lib/active_record/relation/finder_methods.rb, line 158
def all(*args)
  args.any? ? apply_finder_options(args.first).to_a : to_a
end
exists?(id = false)

Returns true if a record exists in the table that matches the id or conditions given, or false otherwise. The argument can take five 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 ['color = ?', 'red']).

  • Hash - Finds the record that matches these find-style conditions (such as {:color => 'red'}).

  • 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\''.

Examples

Person.exists?(5)
Person.exists?('5')
Person.exists?(:name => "David")
Person.exists?(['name LIKE ?', "%#{query}%"])
Person.exists?
# File activerecord/lib/active_record/relation/finder_methods.rb, line 187
def exists?(id = false)
  id = id.id if ActiveRecord::Base === id
  return false if id.nil?

  join_dependency = construct_join_dependency_for_association_find
  relation = construct_relation_for_association_find(join_dependency)
  relation = relation.except(:select, :order).select("1").limit(1)

  case id
  when Array, Hash
    relation = relation.where(id)
  else
    relation = relation.where(table[primary_key].eq(id)) if id
  end

  connection.select_value(relation, "#{name} Exists") ? true : false
end
find(*args)

Find operates with four different retrieval approaches:

  • 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.

  • Find first - This will return the first record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned. Use Model.find(:first, *args) or its shortcut Model.first(*args).

  • Find last - This will return the last record matched by the options used. These options can either be specific conditions or merely an order. If no record can be matched, nil is returned. Use Model.find(:last, *args) or its shortcut Model.last(*args).

  • Find all - This will return all the records matched by the options used. If no records are found, an empty array is returned. Use Model.find(:all, *args) or its shortcut Model.all(*args).

All approaches accept an options hash as their last parameter.

Options

  • :conditions - An SQL fragment like "administrator = 1", ["user_name = ?", username], or ["user_name = :user_name", { :user_name => user_name }]. See conditions in the intro.

  • :order - An SQL fragment like "created_at DESC, name".

  • :group - An attribute name by which the result should be grouped. Uses the GROUP BY SQL-clause.

  • :having - Combined with :group this can be used to filter the records that a GROUP BY returns. Uses the HAVING SQL-clause.

  • :limit - An integer determining the limit on the number of rows that should be returned.

  • :offset - An integer determining the offset from where the rows should be fetched. So at 5, it would skip rows 0 through 4.

  • :joins - Either an SQL fragment for additional joins like "LEFT JOIN comments ON comments.post_id = id" (rarely needed), named associations in the same form used for the :include option, which will perform an INNER JOIN on the associated table(s), or an array containing a mixture of both strings and named associations. If the value is a string, then the records will be returned read-only since they will have attributes that do not correspond to the table's columns. Pass :readonly => false to override.

  • :include - Names associations that should be loaded alongside. The symbols named refer to already defined associations. See eager loading under Associations.

  • :select - By default, this is "*" as in "SELECT * FROM", but can be changed if you, for example, want to do a join but not include the joined columns. Takes a string with the SELECT SQL fragment (e.g. "id, name").

  • :from - By default, this is the table name of the class, but can be changed to an alternate table name (or even the name of a database view).

  • :readonly - Mark the returned records read-only so they cannot be saved or updated.

  • :lock - An SQL fragment like "FOR UPDATE" or "LOCK IN SHARE MODE". :lock => true gives connection's default exclusive lock, usually "FOR UPDATE".

Examples

# find by id
Person.find(1)       # returns the object for ID = 1
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)

Note that returned records may not be in the same order as the ids you provide since database rows are unordered. Give an explicit :order to ensure the results are sorted.

Examples

# find first
Person.first # returns the first object fetched by SELECT * FROM people
Person.where(["user_name = ?", user_name]).first
Person.where(["user_name = :u", { :u => user_name }]).first
Person.order("created_on DESC").offset(5).first

# find last
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

# find all
Person.all # returns an array of objects for all the rows fetched by SELECT * FROM people
Person.where(["category IN (?)", categories]).limit(50).all
Person.where({ :friends => ["Bob", "Steve", "Fred"] }).all
Person.offset(10).limit(10).all
Person.includes([:account, :friends]).all
Person.group("category").all

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
# File activerecord/lib/active_record/relation/finder_methods.rb, line 95
def find(*args)
  return to_a.find { |*block_args| yield(*block_args) } if block_given?

  options = args.extract_options!

  if options.present?
    apply_finder_options(options).find(*args)
  else
    case args.first
    when :first, :last, :all
      send(args.first)
    else
      find_with_ids(*args)
    end
  end
end
first(*args)

A convenience wrapper for find(:first, *args). You can pass in all the same arguments to this method as you can to find(:first).

# File activerecord/lib/active_record/relation/finder_methods.rb, line 114
def first(*args)
  if args.any?
    if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
      limit(*args).to_a
    else
      apply_finder_options(args.first).first
    end
  else
    find_first
  end
end
first!()

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

# File activerecord/lib/active_record/relation/finder_methods.rb, line 128
def first!
  first or raise RecordNotFound
end
last(*args)

A convenience wrapper for find(:last, *args). You can pass in all the same arguments to this method as you can to find(:last).

# File activerecord/lib/active_record/relation/finder_methods.rb, line 134
def last(*args)
  if args.any?
    if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
      if order_values.empty?
        order("#{primary_key} DESC").limit(*args).reverse
      else
        to_a.last(*args)
      end
    else
      apply_finder_options(args.first).last
    end
  else
    find_last
  end
end
last!()

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

# File activerecord/lib/active_record/relation/finder_methods.rb, line 152
def last!
  last or raise RecordNotFound
end
Instance Protected methods
apply_join_dependency(relation, join_dependency)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 233
def apply_join_dependency(relation, join_dependency)
  join_dependency.join_associations.each do |association|
    relation = association.join_relation(relation)
  end

  limitable_reflections = using_limitable_reflections?(join_dependency.reflections)

  if !limitable_reflections && relation.limit_value
    limited_id_condition = construct_limited_ids_condition(relation.except(:select))
    relation = relation.where(limited_id_condition)
  end

  relation = relation.except(:limit, :offset) unless limitable_reflections

  relation
end
construct_join_dependency_for_association_find()
# File activerecord/lib/active_record/relation/finder_methods.rb, line 216
def construct_join_dependency_for_association_find
  including = (@eager_load_values + @includes_values).uniq
  ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
end
construct_limited_ids_condition(relation)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 250
def construct_limited_ids_condition(relation)
  orders = relation.order_values.map { |val| val.presence }.compact
  values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)

  relation = relation.dup

  ids_array = relation.select(values).collect {|row| row[primary_key]}
  ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
end
construct_relation_for_association_calculations()
# File activerecord/lib/active_record/relation/finder_methods.rb, line 221
def construct_relation_for_association_calculations
  including = (@eager_load_values + @includes_values).uniq
  join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
  relation = except(:includes, :eager_load, :preload)
  apply_join_dependency(relation, join_dependency)
end
construct_relation_for_association_find(join_dependency)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 228
def construct_relation_for_association_find(join_dependency)
  relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns)
  apply_join_dependency(relation, join_dependency)
end
find_by_attributes(match, attributes, *args)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 260
def find_by_attributes(match, attributes, *args)
  conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
  result = where(conditions).send(match.finder)

  if match.bang? && result.blank?
    raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
  else
    yield(result) if block_given?
    result
  end
end
find_first()
# File activerecord/lib/active_record/relation/finder_methods.rb, line 372
def find_first
  if loaded?
    @records.first
  else
    @first ||= limit(1).to_a[0]
  end
end
find_last()
# File activerecord/lib/active_record/relation/finder_methods.rb, line 380
def find_last
  if loaded?
    @records.last
  else
    @last ||=
      if offset_value || limit_value
        to_a.last
      else
        reverse_order.limit(1).to_a[0]
      end
  end
end
find_one(id)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 317
def find_one(id)
  id = id.id if ActiveRecord::Base === id

  if IdentityMap.enabled? && where_values.blank? &&
    limit_value.blank? && order_values.blank? &&
    includes_values.blank? && preload_values.blank? &&
    readonly_value.nil? && joins_values.blank? &&
    !@klass.locking_enabled? &&
    record = IdentityMap.get(@klass, id)
    return record
  end

  column = columns_hash[primary_key]

  substitute = connection.substitute_at(column, @bind_values.length)
  relation = where(table[primary_key].eq(substitute))
  relation.bind_values = [[column, id]]
  record = relation.first

  unless record
    conditions = arel.where_sql
    conditions = " [#{conditions}]" if conditions
    raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}"
  end

  record
end
find_or_instantiator_by_attributes(match, attributes, *args)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 272
def find_or_instantiator_by_attributes(match, attributes, *args)
  options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
  protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
  args.each_with_index do |arg, i|
    if arg.is_a?(Hash)
      protected_attributes_for_create = args[i].with_indifferent_access
    else
      unprotected_attributes_for_create[attributes[i]] = args[i]
    end
  end

  conditions = (protected_attributes_for_create.merge(unprotected_attributes_for_create)).slice(*attributes).symbolize_keys

  record = where(conditions).first

  unless record
    record = @klass.new(protected_attributes_for_create, options) do |r|
      r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
    end
    yield(record) if block_given?
    record.send(match.save_method) if match.save_record?
  end

  record
end
find_some(ids)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 345
def find_some(ids)
  result = where(table[primary_key].in(ids)).all

  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
    conditions = arel.where_sql
    conditions = " [#{conditions}]" if conditions

    error = "Couldn't find all #{@klass.name.pluralize} with IDs "
    error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
    raise RecordNotFound, error
  end
end
find_with_associations()
# File activerecord/lib/active_record/relation/finder_methods.rb, line 207
def find_with_associations
  join_dependency = construct_join_dependency_for_association_find
  relation = construct_relation_for_association_find(join_dependency)
  rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
  join_dependency.instantiate(rows)
rescue ThrowResult
  []
end
find_with_ids(*ids)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 298
def find_with_ids(*ids)
  return to_a.find { |*block_args| yield(*block_args) } if block_given?

  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
end
using_limitable_reflections?(reflections)
# File activerecord/lib/active_record/relation/finder_methods.rb, line 393
def using_limitable_reflections?(reflections)
  reflections.none? { |r| r.collection? }
end