提交 592e6b7e 编写于 作者: R Ryuta Kamizono

Remove unnecessary ordinal methods for collection association

Currently `CollectionProxy` inherits `Relation` therefore we can use
its own methods rather than delegating to collection association.
上级 6568cfd7
...@@ -111,50 +111,6 @@ def find(*args) ...@@ -111,50 +111,6 @@ def find(*args)
end end
end end
def first(limit = nil)
find_nth_or_last(:first, limit)
end
def second
find_nth_or_last(:second)
end
def third
find_nth_or_last(:third)
end
def fourth
find_nth_or_last(:fourth)
end
def fifth
find_nth_or_last(:fifth)
end
def forty_two
find_nth_or_last(:forty_two)
end
def third_to_last
find_nth_or_last(:third_to_last)
end
def second_to_last
find_nth_or_last(:second_to_last)
end
def last(limit = nil)
find_nth_or_last(:last, limit)
end
def take(limit = nil)
if find_from_target?
limit ? load_target.take(limit) : load_target.first
else
scope.take(limit)
end
end
def build(attributes = {}, &block) def build(attributes = {}, &block)
if attributes.is_a?(Array) if attributes.is_a?(Array)
attributes.collect { |attr| build(attr, &block) } attributes.collect { |attr| build(attr, &block) }
...@@ -453,6 +409,12 @@ def null_scope? ...@@ -453,6 +409,12 @@ def null_scope?
owner.new_record? && !foreign_key_present? owner.new_record? && !foreign_key_present?
end end
def find_from_target?
loaded? ||
owner.new_record? ||
target.any? { |record| record.new_record? || record.changed? }
end
private private
def find_target def find_target
...@@ -599,21 +561,6 @@ def callbacks_for(callback_name) ...@@ -599,21 +561,6 @@ def callbacks_for(callback_name)
owner.class.send(full_callback_name) owner.class.send(full_callback_name)
end end
# Should we deal with assoc.first or assoc.last by issuing an independent query to
# the database, or by getting the target, and then taking the first/last item from that?
#
# If the args is just a non-empty options hash, go to the database.
#
# Otherwise, go to the database only if none of the following are true:
# * target already loaded
# * owner is new record
# * target contains new or changed record(s)
def find_from_target?
loaded? ||
owner.new_record? ||
target.any? { |record| record.new_record? || record.changed? }
end
def include_in_memory?(record) def include_in_memory?(record)
if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection) if reflection.is_a?(ActiveRecord::Reflection::ThroughReflection)
assoc = owner.association(reflection.through_reflection.name) assoc = owner.association(reflection.through_reflection.name)
...@@ -640,12 +587,6 @@ def find_by_scan(*args) ...@@ -640,12 +587,6 @@ def find_by_scan(*args)
load_target.select { |r| ids.include?(r.id.to_s) } load_target.select { |r| ids.include?(r.id.to_s) }
end end
end end
# Fetches the first/last using SQL if possible, otherwise from the target array.
def find_nth_or_last(ordinal, limit = nil)
collection = find_from_target? ? load_target : scope
limit ? collection.send(ordinal, limit) : collection.send(ordinal)
end
end end
end end
end end
...@@ -140,6 +140,12 @@ def find(*args, &block) ...@@ -140,6 +140,12 @@ def find(*args, &block)
@association.find(*args, &block) @association.find(*args, &block)
end end
##
# :method: first
#
# :call-seq:
# first(limit = nil)
#
# Returns the first record, or the first +n+ records, from the collection. # Returns the first record, or the first +n+ records, from the collection.
# If the collection is empty, the first form returns +nil+, and the second # If the collection is empty, the first form returns +nil+, and the second
# form returns an empty array. # form returns an empty array.
...@@ -166,45 +172,63 @@ def find(*args, &block) ...@@ -166,45 +172,63 @@ def find(*args, &block)
# another_person_without.pets # => [] # another_person_without.pets # => []
# another_person_without.pets.first # => nil # another_person_without.pets.first # => nil
# another_person_without.pets.first(3) # => [] # another_person_without.pets.first(3) # => []
def first(limit = nil)
@association.first(limit)
end
##
# :method: second
#
# :call-seq:
# second()
#
# Same as #first except returns only the second record. # Same as #first except returns only the second record.
def second
@association.second
end
##
# :method: third
#
# :call-seq:
# third()
#
# Same as #first except returns only the third record. # Same as #first except returns only the third record.
def third
@association.third
end
##
# :method: fourth
#
# :call-seq:
# fourth()
#
# Same as #first except returns only the fourth record. # Same as #first except returns only the fourth record.
def fourth
@association.fourth
end
##
# :method: fifth
#
# :call-seq:
# fifth()
#
# Same as #first except returns only the fifth record. # Same as #first except returns only the fifth record.
def fifth
@association.fifth
end
##
# :method: forty_two
#
# :call-seq:
# forty_two()
#
# Same as #first except returns only the forty second record. # Same as #first except returns only the forty second record.
# Also known as accessing "the reddit". # Also known as accessing "the reddit".
def forty_two
@association.forty_two
end
##
# :method: third_to_last
#
# :call-seq:
# third_to_last()
#
# Same as #first except returns only the third-to-last record. # Same as #first except returns only the third-to-last record.
def third_to_last
@association.third_to_last
end
##
# :method: second_to_last
#
# :call-seq:
# second_to_last()
#
# Same as #first except returns only the second-to-last record. # Same as #first except returns only the second-to-last record.
def second_to_last
@association.second_to_last
end
# Returns the last record, or the last +n+ records, from the collection. # Returns the last record, or the last +n+ records, from the collection.
# If the collection is empty, the first form returns +nil+, and the second # If the collection is empty, the first form returns +nil+, and the second
...@@ -233,7 +257,8 @@ def second_to_last ...@@ -233,7 +257,8 @@ def second_to_last
# another_person_without.pets.last # => nil # another_person_without.pets.last # => nil
# another_person_without.pets.last(3) # => [] # another_person_without.pets.last(3) # => []
def last(limit = nil) def last(limit = nil)
@association.last(limit) load_target if find_from_target?
super
end end
# Gives a record (or N records if a parameter is supplied) from the collection # Gives a record (or N records if a parameter is supplied) from the collection
...@@ -262,7 +287,8 @@ def last(limit = nil) ...@@ -262,7 +287,8 @@ def last(limit = nil)
# another_person_without.pets.take # => nil # another_person_without.pets.take # => nil
# another_person_without.pets.take(2) # => [] # another_person_without.pets.take(2) # => []
def take(limit = nil) def take(limit = nil)
@association.take(limit) load_target if find_from_target?
super
end end
# Returns a new object of the collection type that has been instantiated # Returns a new object of the collection type that has been instantiated
...@@ -1078,12 +1104,28 @@ def reset ...@@ -1078,12 +1104,28 @@ def reset
self self
end end
protected
def find_nth_with_limit(index, limit)
load_target if find_from_target?
super
end
def find_nth_from_last(index)
load_target if find_from_target?
super
end
private private
def null_scope? def null_scope?
@association.null_scope? @association.null_scope?
end end
def find_from_target?
@association.find_from_target?
end
def exec_queries def exec_queries
load_target load_target
end end
......
...@@ -97,7 +97,7 @@ def find_by!(arg, *args) ...@@ -97,7 +97,7 @@ def find_by!(arg, *args)
# Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5 # Person.take(5) # returns 5 objects fetched by SELECT * FROM people LIMIT 5
# Person.where(["name LIKE '%?'", name]).take # Person.where(["name LIKE '%?'", name]).take
def take(limit = nil) def take(limit = nil)
limit ? limit(limit).to_a : find_take limit ? find_take_with_limit(limit) : find_take
end end
# Same as #take but raises ActiveRecord::RecordNotFound if no record # Same as #take but raises ActiveRecord::RecordNotFound if no record
...@@ -526,13 +526,21 @@ def find_take ...@@ -526,13 +526,21 @@ def find_take
end end
end end
def find_take_with_limit(limit)
if loaded?
records.take(limit)
else
limit(limit).to_a
end
end
def find_nth(index) def find_nth(index)
@offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first @offsets[offset_index + index] ||= find_nth_with_limit(index, 1).first
end end
def find_nth_with_limit(index, limit) def find_nth_with_limit(index, limit)
if loaded? if loaded?
records[index, limit] records[index, limit] || []
else else
relation = if order_values.empty? && primary_key relation = if order_values.empty? && primary_key
order(arel_attribute(primary_key).asc) order(arel_attribute(primary_key).asc)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册