aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/lib/active_record/relation
diff options
context:
space:
mode:
Diffstat (limited to 'activerecord/lib/active_record/relation')
-rw-r--r--activerecord/lib/active_record/relation/batches.rb6
-rw-r--r--activerecord/lib/active_record/relation/calculations.rb12
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb73
-rw-r--r--activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb2
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb12
5 files changed, 66 insertions, 39 deletions
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index 54587ae18e..de005e2810 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -204,15 +204,15 @@ module ActiveRecord
yield yielded_relation
break if ids.length < of
- batch_relation = relation.where(table[primary_key].gt(primary_key_offset))
+ batch_relation = relation.where(arel_attribute(primary_key).gt(primary_key_offset))
end
end
private
def apply_limits(relation, start, finish)
- relation = relation.where(table[primary_key].gteq(start)) if start
- relation = relation.where(table[primary_key].lteq(finish)) if finish
+ relation = relation.where(arel_attribute(primary_key).gteq(start)) if start
+ relation = relation.where(arel_attribute(primary_key).lteq(finish)) if finish
relation
end
diff --git a/activerecord/lib/active_record/relation/calculations.rb b/activerecord/lib/active_record/relation/calculations.rb
index f45844a9ea..54c9af4898 100644
--- a/activerecord/lib/active_record/relation/calculations.rb
+++ b/activerecord/lib/active_record/relation/calculations.rb
@@ -155,15 +155,7 @@ module ActiveRecord
# See also #ids.
#
def pluck(*column_names)
- column_names.map! do |column_name|
- if column_name.is_a?(Symbol) && attribute_alias?(column_name)
- attribute_alias(column_name)
- else
- column_name.to_s
- end
- end
-
- if loaded? && (column_names - @klass.column_names).empty?
+ if loaded? && (column_names.map(&:to_s) - @klass.attribute_names - @klass.attribute_aliases.keys).empty?
return @records.pluck(*column_names)
end
@@ -172,7 +164,7 @@ module ActiveRecord
else
relation = spawn
relation.select_values = column_names.map { |cn|
- columns_hash.key?(cn) ? arel_table[cn] : cn
+ @klass.has_attribute?(cn) || @klass.attribute_alias?(cn) ? arel_attribute(cn) : cn
}
result = klass.connection.select_all(relation.arel, nil, bound_attributes)
result.cast_values(klass.attribute_types)
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 5d4a045097..90a6a466fd 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -145,23 +145,15 @@ module ActiveRecord
#
# [#<Person id:4>, #<Person id:3>, #<Person id:2>]
def last(limit = nil)
- return find_last(limit) if loaded?
-
- result = order_values.empty? && primary_key ? order(arel_table[primary_key].desc) : reverse_order
- result = result.limit!(limit || 1)
- limit ? result.reverse : result.first
- rescue ActiveRecord::IrreversibleOrderError
- ActiveSupport::Deprecation.warn(<<-WARNING.squish)
- Finding a last element by loading the relation when SQL ORDER
- can not be reversed is deprecated.
- Rails 5.1 will raise ActiveRecord::IrreversibleOrderError in this case.
- Please call `to_a.last` if you still want to load the relation.
- WARNING
- find_last(limit)
- end
-
- def find_last(limit)
- limit ? to_a.last(limit) : to_a.last
+ if limit
+ if order_values.empty? && primary_key
+ order(arel_attribute(primary_key).desc).limit(limit).reverse
+ else
+ to_a.last(limit)
+ end
+ else
+ find_last
+ end
end
# Same as #last but raises ActiveRecord::RecordNotFound if no record
@@ -250,6 +242,38 @@ module ActiveRecord
find_nth! 41
end
+ # Find the third-to-last record.
+ # If no order is defined it will order by primary key.
+ #
+ # Person.third_to_last # returns the third-to-last object fetched by SELECT * FROM people
+ # Person.offset(3).third_to_last # returns the third-to-last object from OFFSET 3
+ # Person.where(["user_name = :u", { u: user_name }]).third_to_last
+ def third_to_last
+ find_nth -3
+ end
+
+ # Same as #third_to_last but raises ActiveRecord::RecordNotFound if no record
+ # is found.
+ def third_to_last!
+ find_nth! -3
+ end
+
+ # Find the second-to-last record.
+ # If no order is defined it will order by primary key.
+ #
+ # Person.second_to_last # returns the second-to-last object fetched by SELECT * FROM people
+ # Person.offset(3).second_to_last # returns the second-to-last object from OFFSET 3
+ # Person.where(["user_name = :u", { u: user_name }]).second_to_last
+ def second_to_last
+ find_nth -2
+ end
+
+ # Same as #second_to_last but raises ActiveRecord::RecordNotFound if no record
+ # is found.
+ def second_to_last!
+ find_nth! -2
+ end
+
# Returns true if a record exists in the table that matches the +id+ or
# conditions given, or false otherwise. The argument can take six forms:
#
@@ -522,7 +546,7 @@ module ActiveRecord
# 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)
+ order(arel_attribute(primary_key).asc)
else
self
end
@@ -531,6 +555,19 @@ module ActiveRecord
relation.limit(limit).to_a
end
+ def find_last
+ if loaded?
+ @records.last
+ else
+ @last ||=
+ if limit_value
+ to_a.last
+ else
+ reverse_order.limit(1).to_a.first
+ end
+ end
+ end
+
private
def find_nth_with_limit_and_offset(index, limit, offset:) # :nodoc:
diff --git a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
index 063150958a..8a910a82fe 100644
--- a/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
+++ b/activerecord/lib/active_record/relation/predicate_builder/relation_handler.rb
@@ -3,7 +3,7 @@ module ActiveRecord
class RelationHandler # :nodoc:
def call(attribute, value)
if value.select_values.empty?
- value = value.select(value.klass.arel_table[value.klass.primary_key])
+ value = value.select(value.arel_attribute(value.klass.primary_key))
end
attribute.in(value.arel)
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 8ef9f9f627..91bfa4d131 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -1093,8 +1093,8 @@ module ActiveRecord
def arel_columns(columns)
columns.map do |field|
- if (Symbol === field || String === field) && columns_hash.key?(field.to_s) && !from_clause.value
- arel_table[field]
+ if (Symbol === field || String === field) && (klass.has_attribute?(field) || klass.attribute_alias?(field)) && !from_clause.value
+ arel_attribute(field)
elsif Symbol === field
connection.quote_table_name(field.to_s)
else
@@ -1105,7 +1105,7 @@ module ActiveRecord
def reverse_sql_order(order_query)
if order_query.empty?
- return [table[primary_key].desc] if primary_key
+ return [arel_attribute(primary_key).desc] if primary_key
raise IrreversibleOrderError,
"Relation has no current order and table has no primary key to be used as default order"
end
@@ -1170,12 +1170,10 @@ module ActiveRecord
order_args.map! do |arg|
case arg
when Symbol
- arg = klass.attribute_alias(arg) if klass.attribute_alias?(arg)
- table[arg].asc
+ arel_attribute(arg).asc
when Hash
arg.map { |field, dir|
- field = klass.attribute_alias(field) if klass.attribute_alias?(field)
- table[field].send(dir.downcase)
+ arel_attribute(field).send(dir.downcase)
}
else
arg