Files

Class Index [+]

Quicksearch

ActiveRecord::FinderMethods

Public Instance Methods

all(*args) click to toggle source

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 lib/active_record/relation/finder_methods.rb, line 158
158:     def all(*args)
159:       args.any? ? apply_finder_options(args.first).to_a : to_a
160:     end
exists?(id = false) 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 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 lib/active_record/relation/finder_methods.rb, line 187
187:     def exists?(id = false)
188:       id = id.id if ActiveRecord::Base === id
189:       return false if id.nil?
190: 
191:       join_dependency = construct_join_dependency_for_association_find
192:       relation = construct_relation_for_association_find(join_dependency)
193:       relation = relation.except(:select, :order).select("1 AS one").limit(1)
194: 
195:       case id
196:       when Array, Hash
197:         relation = relation.where(id)
198:       else
199:         relation = relation.where(table[primary_key].eq(id)) if id
200:       end
201: 
202:       connection.select_value(relation, "#{name} Exists") ? true : false
203:     rescue ThrowResult
204:       false
205:     end
find(*args) click to toggle source

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 lib/active_record/relation/finder_methods.rb, line 95
 95:     def find(*args)
 96:       return to_a.find { |*block_args| yield(*block_args) } if block_given?
 97: 
 98:       options = args.extract_options!
 99: 
100:       if options.present?
101:         apply_finder_options(options).find(*args)
102:       else
103:         case args.first
104:         when :first, :last, :all
105:           send(args.first)
106:         else
107:           find_with_ids(*args)
108:         end
109:       end
110:     end
first(*args) click to toggle source

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 lib/active_record/relation/finder_methods.rb, line 114
114:     def first(*args)
115:       if args.any?
116:         if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
117:           limit(*args).to_a
118:         else
119:           apply_finder_options(args.first).first
120:         end
121:       else
122:         find_first
123:       end
124:     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 128
128:     def first!
129:       first or raise RecordNotFound
130:     end
last(*args) click to toggle source

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 lib/active_record/relation/finder_methods.rb, line 134
134:     def last(*args)
135:       if args.any?
136:         if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
137:           if order_values.empty?
138:             order("#{primary_key} DESC").limit(*args).reverse
139:           else
140:             to_a.last(*args)
141:           end
142:         else
143:           apply_finder_options(args.first).last
144:         end
145:       else
146:         find_last
147:       end
148:     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 152
152:     def last!
153:       last or raise RecordNotFound
154:     end

Protected Instance Methods

apply_join_dependency(relation, join_dependency) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 235
235:     def apply_join_dependency(relation, join_dependency)
236:       join_dependency.join_associations.each do |association|
237:         relation = association.join_relation(relation)
238:       end
239: 
240:       limitable_reflections = using_limitable_reflections?(join_dependency.reflections)
241: 
242:       if !limitable_reflections && relation.limit_value
243:         limited_id_condition = construct_limited_ids_condition(relation.except(:select))
244:         relation = relation.where(limited_id_condition)
245:       end
246: 
247:       relation = relation.except(:limit, :offset) unless limitable_reflections
248: 
249:       relation
250:     end
construct_join_dependency_for_association_find() click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 218
218:     def construct_join_dependency_for_association_find
219:       including = (@eager_load_values + @includes_values).uniq
220:       ActiveRecord::Associations::JoinDependency.new(@klass, including, [])
221:     end
construct_limited_ids_condition(relation) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 252
252:     def construct_limited_ids_condition(relation)
253:       orders = relation.order_values.map { |val| val.presence }.compact
254:       values = @klass.connection.distinct("#{@klass.connection.quote_table_name table_name}.#{primary_key}", orders)
255: 
256:       relation = relation.dup
257: 
258:       ids_array = relation.select(values).collect {|row| row[primary_key]}
259:       ids_array.empty? ? raise(ThrowResult) : table[primary_key].in(ids_array)
260:     end
construct_relation_for_association_calculations() click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 223
223:     def construct_relation_for_association_calculations
224:       including = (@eager_load_values + @includes_values).uniq
225:       join_dependency = ActiveRecord::Associations::JoinDependency.new(@klass, including, arel.froms.first)
226:       relation = except(:includes, :eager_load, :preload)
227:       apply_join_dependency(relation, join_dependency)
228:     end
construct_relation_for_association_find(join_dependency) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 230
230:     def construct_relation_for_association_find(join_dependency)
231:       relation = except(:includes, :eager_load, :preload, :select).select(join_dependency.columns)
232:       apply_join_dependency(relation, join_dependency)
233:     end
find_by_attributes(match, attributes, *args) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 262
262:     def find_by_attributes(match, attributes, *args)
263:       conditions = Hash[attributes.map {|a| [a, args[attributes.index(a)]]}]
264:       result = where(conditions).send(match.finder)
265: 
266:       if match.bang? && result.blank?
267:         raise RecordNotFound, "Couldn't find #{@klass.name} with #{conditions.to_a.collect {|p| p.join(' = ')}.join(', ')}"
268:       else
269:         yield(result) if block_given?
270:         result
271:       end
272:     end
find_first() click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 374
374:     def find_first
375:       if loaded?
376:         @records.first
377:       else
378:         @first ||= limit(1).to_a[0]
379:       end
380:     end
find_last() click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 382
382:     def find_last
383:       if loaded?
384:         @records.last
385:       else
386:         @last ||=
387:           if offset_value || limit_value
388:             to_a.last
389:           else
390:             reverse_order.limit(1).to_a[0]
391:           end
392:       end
393:     end
find_one(id) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 319
319:     def find_one(id)
320:       id = id.id if ActiveRecord::Base === id
321: 
322:       if IdentityMap.enabled? && where_values.blank? &&
323:         limit_value.blank? && order_values.blank? &&
324:         includes_values.blank? && preload_values.blank? &&
325:         readonly_value.nil? && joins_values.blank? &&
326:         !@klass.locking_enabled? &&
327:         record = IdentityMap.get(@klass, id)
328:         return record
329:       end
330: 
331:       column = columns_hash[primary_key]
332: 
333:       substitute = connection.substitute_at(column, @bind_values.length)
334:       relation = where(table[primary_key].eq(substitute))
335:       relation.bind_values = [[column, id]]
336:       record = relation.first
337: 
338:       unless record
339:         conditions = arel.where_sql
340:         conditions = " [#{conditions}]" if conditions
341:         raise RecordNotFound, "Couldn't find #{@klass.name} with #{primary_key}=#{id}#{conditions}"
342:       end
343: 
344:       record
345:     end
find_or_instantiator_by_attributes(match, attributes, *args) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 274
274:     def find_or_instantiator_by_attributes(match, attributes, *args)
275:       options = args.size > 1 && args.last(2).all?{ |a| a.is_a?(Hash) } ? args.extract_options! : {}
276:       protected_attributes_for_create, unprotected_attributes_for_create = {}, {}
277:       args.each_with_index do |arg, i|
278:         if arg.is_a?(Hash)
279:           protected_attributes_for_create = args[i].with_indifferent_access
280:         else
281:           unprotected_attributes_for_create[attributes[i]] = args[i]
282:         end
283:       end
284: 
285:       conditions = (protected_attributes_for_create.merge(unprotected_attributes_for_create)).slice(*attributes).symbolize_keys
286: 
287:       record = where(conditions).first
288: 
289:       unless record
290:         record = @klass.new(protected_attributes_for_create, options) do |r|
291:           r.assign_attributes(unprotected_attributes_for_create, :without_protection => true)
292:         end
293:         yield(record) if block_given?
294:         record.send(match.save_method) if match.save_record?
295:       end
296: 
297:       record
298:     end
find_some(ids) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 347
347:     def find_some(ids)
348:       result = where(table[primary_key].in(ids)).all
349: 
350:       expected_size =
351:         if @limit_value && ids.size > @limit_value
352:           @limit_value
353:         else
354:           ids.size
355:         end
356: 
357:       # 11 ids with limit 3, offset 9 should give 2 results.
358:       if @offset_value && (ids.size - @offset_value < expected_size)
359:         expected_size = ids.size - @offset_value
360:       end
361: 
362:       if result.size == expected_size
363:         result
364:       else
365:         conditions = arel.where_sql
366:         conditions = " [#{conditions}]" if conditions
367: 
368:         error = "Couldn't find all #{@klass.name.pluralize} with IDs "
369:         error << "(#{ids.join(", ")})#{conditions} (found #{result.size} results, but was looking for #{expected_size})"
370:         raise RecordNotFound, error
371:       end
372:     end
find_with_associations() click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 209
209:     def find_with_associations
210:       join_dependency = construct_join_dependency_for_association_find
211:       relation = construct_relation_for_association_find(join_dependency)
212:       rows = connection.select_all(relation, 'SQL', relation.bind_values.dup)
213:       join_dependency.instantiate(rows)
214:     rescue ThrowResult
215:       []
216:     end
find_with_ids(*ids) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 300
300:     def find_with_ids(*ids)
301:       return to_a.find { |*block_args| yield(*block_args) } if block_given?
302: 
303:       expects_array = ids.first.kind_of?(Array)
304:       return ids.first if expects_array && ids.first.empty?
305: 
306:       ids = ids.flatten.compact.uniq
307: 
308:       case ids.size
309:       when 0
310:         raise RecordNotFound, "Couldn't find #{@klass.name} without an ID"
311:       when 1
312:         result = find_one(ids.first)
313:         expects_array ? [ result ] : result
314:       else
315:         find_some(ids)
316:       end
317:     end
using_limitable_reflections?(reflections) click to toggle source
     # File lib/active_record/relation/finder_methods.rb, line 395
395:     def using_limitable_reflections?(reflections)
396:       reflections.none? { |r| r.collection? }
397:     end

Disabled; run with --debug to generate this.

[Validate]

Generated with the Darkfish Rdoc Generator 1.1.6.