aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record
diff options
context:
space:
mode:
authorBen Woosley <ben.woosley@gmail.com>2015-10-23 16:13:36 -0500
committerBen Woosley <ben.woosley@gmail.com>2015-12-24 09:03:28 -0800
commitb42c3255bf22e54f459751d5370e8befc33e84ea (patch)
treec1ed70c11b2999af32f127e265c9de37a0ab1851 /activerecord/lib/active_record
parent16a476e4f8f802774ae7c8dca2e59f4e672dc591 (diff)
downloadrails-b42c3255bf22e54f459751d5370e8befc33e84ea.tar.gz
rails-b42c3255bf22e54f459751d5370e8befc33e84ea.tar.bz2
rails-b42c3255bf22e54f459751d5370e8befc33e84ea.zip
Fix `first(limit)` to take advantage of `loaded?` records if available
I realized that `first(2)`, etc. was unnecessarily querying for the records when they were already preloaded. This was because `find_nth_with_limit` can not know which `@records` to return because it conflates the `offset` and `index` into a single variable, while the `@records` only needs the `index` itself to select the proper record. Because `find_nth` and `find_nth_with_limit` are public methods, I instead introduced a private method `find_nth_with_limit_and_offset` which is called internally and handles the `loaded?` checking. Once the `offset` argument is removed from `find_nth`, `find_nth_with_limit_and_offset` can be collapsed into `find_nth_with_limit`, with `offset` always equal to `offset_index`.
Diffstat (limited to 'activerecord/lib/active_record')
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb25
1 files changed, 20 insertions, 5 deletions
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 4a0867289e..3cbb12a09d 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -117,7 +117,7 @@ module ActiveRecord
#
def first(limit = nil)
if limit
- find_nth_with_limit(offset_index, limit)
+ find_nth_with_limit_and_offset(0, limit, offset: offset_index)
else
find_nth 0
end
@@ -492,6 +492,9 @@ module ActiveRecord
if loaded?
@records[index]
else
+ # TODO: once the offset argument is removed we rely on offset_index
+ # within find_nth_with_limit, rather than pass it in via
+ # find_nth_with_limit_and_offset
if offset
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Passing an offset argument to find_nth is deprecated,
@@ -500,8 +503,7 @@ module ActiveRecord
else
offset = offset_index
end
- offset += index
- @offsets[offset] ||= find_nth_with_limit(offset, 1).first
+ @offsets[offset + index] ||= find_nth_with_limit_and_offset(index, 1, offset: offset).first
end
end
@@ -509,14 +511,16 @@ module ActiveRecord
find_nth(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)
+ def find_nth_with_limit(index, limit)
+ # TODO: once the offset argument is removed from find_nth,
+ # find_nth_with_limit_and_offset can be merged into this method
relation = if order_values.empty? && primary_key
order(arel_table[primary_key].asc)
else
self
end
- relation = relation.offset(offset) unless offset.zero?
+ relation = relation.offset(index) unless index.zero?
relation.limit(limit).to_a
end
@@ -532,5 +536,16 @@ module ActiveRecord
end
end
end
+
+ private
+
+ def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
+ if loaded?
+ @records[index, limit]
+ else
+ index += offset
+ find_nth_with_limit(index, limit)
+ end
+ end
end
end