diff options
Diffstat (limited to 'activerecord/lib/active_record/relation/finder_methods.rb')
-rw-r--r-- | activerecord/lib/active_record/relation/finder_methods.rb | 57 |
1 files changed, 35 insertions, 22 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 0c9c761f97..088bc203b7 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -1,4 +1,5 @@ require 'active_support/deprecation' +require 'active_support/core_ext/string/filters' module ActiveRecord module FinderMethods @@ -81,12 +82,16 @@ module ActiveRecord # Post.find_by "published_at < ?", 2.weeks.ago def find_by(*args) where(*args).take + rescue RangeError + nil end # Like <tt>find_by</tt>, except that if no record is found, raises # an <tt>ActiveRecord::RecordNotFound</tt> error. def find_by!(*args) where(*args).take! + rescue RangeError + raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range value" end # Gives a record (or N records if a parameter is supplied) without any implied @@ -103,7 +108,7 @@ module ActiveRecord # Same as +take+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. Note that <tt>take!</tt> accepts no arguments. def take! - take or raise RecordNotFound + take or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") end # Find the first record (or first N records if a parameter is supplied). @@ -138,7 +143,7 @@ module ActiveRecord # Same as +first+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. Note that <tt>first!</tt> accepts no arguments. def first! - first or raise RecordNotFound + find_nth! 0 end # Find the last record (or last N records if a parameter is supplied). @@ -171,7 +176,7 @@ module ActiveRecord # Same as +last+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. Note that <tt>last!</tt> accepts no arguments. def last! - last or raise RecordNotFound + last or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") end # Find the second record. @@ -187,7 +192,7 @@ module ActiveRecord # Same as +second+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. def second! - second or raise RecordNotFound + find_nth! 1 end # Find the third record. @@ -203,7 +208,7 @@ module ActiveRecord # Same as +third+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. def third! - third or raise RecordNotFound + find_nth! 2 end # Find the fourth record. @@ -219,7 +224,7 @@ module ActiveRecord # Same as +fourth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. def fourth! - fourth or raise RecordNotFound + find_nth! 3 end # Find the fifth record. @@ -235,7 +240,7 @@ module ActiveRecord # Same as +fifth+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. def fifth! - fifth or raise RecordNotFound + find_nth! 4 end # Find the forty-second record. Also known as accessing "the reddit". @@ -251,7 +256,7 @@ module ActiveRecord # Same as +forty_two+ but raises <tt>ActiveRecord::RecordNotFound</tt> if no record # is found. def forty_two! - forty_two or raise RecordNotFound + find_nth! 41 end # Returns +true+ if a record exists in the table that matches the +id+ or @@ -284,8 +289,10 @@ module ActiveRecord 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`" + ActiveSupport::Deprecation.warn(<<-MSG.squish) + You are passing an instance of ActiveRecord::Base to `exists?`. + Please pass the id of the object by calling `.id` + MSG end return false if !conditions @@ -304,7 +311,7 @@ module ActiveRecord end end - connection.select_value(relation, "#{name} Exists", relation.bind_values) ? true : false + connection.select_value(relation, "#{name} Exists", relation.arel.bind_values + relation.bind_values) ? true : false end # This method is called whenever no records are found with either a single @@ -316,7 +323,7 @@ module ActiveRecord # the expected number of results should be provided in the +expected_size+ # argument. def raise_record_not_found_exception!(ids, result_size, expected_size) #:nodoc: - conditions = arel.where_sql + conditions = arel.where_sql(@klass.arel_engine) conditions = " [#{conditions}]" if conditions if Array(ids).size == 1 @@ -390,7 +397,7 @@ module ActiveRecord else if relation.limit_value limited_ids = limited_ids_for(relation) - limited_ids.empty? ? relation.none! : relation.where!(table[primary_key].in(limited_ids)) + limited_ids.empty? ? relation.none! : relation.where!(primary_key => limited_ids) end relation.except(:limit, :offset) end @@ -401,13 +408,14 @@ module ActiveRecord "#{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(relation.arel, 'SQL', relation.bind_values) + id_rows = @klass.connection.select_all(arel, 'SQL', arel.bind_values + relation.bind_values) id_rows.map {|row| row[primary_key]} end def using_limitable_reflections?(reflections) - reflections.none? { |r| r.collection? } + reflections.none?(&:collection?) end protected @@ -429,19 +437,20 @@ module ActiveRecord else find_some(ids) end + rescue RangeError + raise RecordNotFound, "Couldn't find #{@klass.name} with an out of range ID" end 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`" + ActiveSupport::Deprecation.warn(<<-MSG.squish) + You are passing an instance of ActiveRecord::Base to `find`. + Please pass the id of the object by calling `.id` + MSG 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]] + relation = where(primary_key => id) record = relation.take raise_record_not_found_exception!(id, 0, 1) unless record @@ -450,7 +459,7 @@ module ActiveRecord end def find_some(ids) - result = where(table[primary_key].in(ids)).to_a + result = where(primary_key => ids).to_a expected_size = if limit_value && ids.size > limit_value @@ -488,6 +497,10 @@ module ActiveRecord end end + def find_nth!(index) + find_nth(index, offset_index) or raise RecordNotFound.new("Couldn't find #{@klass.name} with [#{arel.where_sql(@klass.arel_engine)}]") + end + def find_nth_with_limit(offset, limit) relation = if order_values.empty? && primary_key order(arel_table[primary_key].asc) |