- A
- C
- E
- F
- L
- U
A convenience wrapper for find(:all, *args)
. You can pass in
all the same arguments to this method as you can to
find(:all)
.
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 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. UseModel.find(:first, *args)
or its shortcutModel.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. UseModel.find(:last, *args)
or its shortcutModel.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 shortcutModel.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 theGROUP BY
SQL-clause. -
:having
- Combined with:group
this can be used to filter the records that aGROUP BY
returns. Uses theHAVING
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 anINNER 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
A convenience wrapper for find(:first, *args)
. You can pass in
all the same arguments to this method as you can to
find(:first)
.
Same as first
but raises
ActiveRecord::RecordNotFound
if no record is found. Note that
first!
accepts no arguments.
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
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 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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
# 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