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.rb2
-rw-r--r--activerecord/lib/active_record/relation/finder_methods.rb12
-rw-r--r--activerecord/lib/active_record/relation/query_methods.rb74
3 files changed, 77 insertions, 11 deletions
diff --git a/activerecord/lib/active_record/relation/batches.rb b/activerecord/lib/active_record/relation/batches.rb
index ec1176e3dd..2fd89882ff 100644
--- a/activerecord/lib/active_record/relation/batches.rb
+++ b/activerecord/lib/active_record/relation/batches.rb
@@ -62,7 +62,7 @@ module ActiveRecord
start = options.delete(:start).to_i
batch_size = options.delete(:batch_size) || 1000
- relation = relation.except(:order).order(batch_order).limit(batch_size)
+ relation = relation.reorder(batch_order).limit(batch_size)
records = relation.where(table[primary_key].gteq(start)).all
while records.any?
diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb
index 73368aed18..7eeb3dde70 100644
--- a/activerecord/lib/active_record/relation/finder_methods.rb
+++ b/activerecord/lib/active_record/relation/finder_methods.rb
@@ -114,7 +114,7 @@ module ActiveRecord
def first(*args)
if args.any?
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- to_a.first(*args)
+ limit(*args).to_a
else
apply_finder_options(args.first).first
end
@@ -134,7 +134,11 @@ module ActiveRecord
def last(*args)
if args.any?
if args.first.kind_of?(Integer) || (loaded? && !args.first.kind_of?(Hash))
- to_a.last(*args)
+ if order_values.empty? && reorder_value.nil?
+ order("#{primary_key} DESC").limit(*args).reverse
+ else
+ to_a.last(*args)
+ end
else
apply_finder_options(args.first).last
end
@@ -180,7 +184,9 @@ module ActiveRecord
# Person.exists?(:name => "David")
# Person.exists?(['name LIKE ?', "%#{query}%"])
# Person.exists?
- def exists?(id = nil)
+ def exists?(id = false)
+ return false if id.nil?
+
id = id.id if ActiveRecord::Base === id
join_dependency = construct_join_dependency_for_association_find
diff --git a/activerecord/lib/active_record/relation/query_methods.rb b/activerecord/lib/active_record/relation/query_methods.rb
index 1654ae1eac..670ba0987d 100644
--- a/activerecord/lib/active_record/relation/query_methods.rb
+++ b/activerecord/lib/active_record/relation/query_methods.rb
@@ -37,6 +37,35 @@ module ActiveRecord
relation
end
+ # Works in two unique ways.
+ #
+ # First: takes a block so it can be used just like Array#select.
+ #
+ # Model.scoped.select { |m| m.field == value }
+ #
+ # This will build an array of objects from the database for the scope,
+ # converting them into an array and iterating through them using Array#select.
+ #
+ # Second: Modifies the SELECT statement for the query so that only certain
+ # fields are retrieved:
+ #
+ # >> Model.select(:field)
+ # => [#<Model field:value>]
+ #
+ # Although in the above example it looks as though this method returns an
+ # array, it actually returns a relation object and can have other query
+ # methods appended to it, such as the other methods in ActiveRecord::QueryMethods.
+ #
+ # This method will also take multiple parameters:
+ #
+ # >> Model.select(:field, :other_field, :and_one_more)
+ # => [#<Model field: "value", other_field: "value", and_one_more: "value">]
+ #
+ # Any attributes that do not have fields retrieved by a select
+ # will return `nil` when the getter method for that attribute is used:
+ #
+ # >> Model.select(:field).first.other_field
+ # => nil
def select(value = Proc.new)
if block_given?
to_a.select {|*block_args| value.call(*block_args) }
@@ -147,6 +176,42 @@ module ActiveRecord
relation
end
+ # Used to extend a scope with additional methods, either through
+ # a module or through a block provided.
+ #
+ # The object returned is a relation, which can be further extended.
+ #
+ # === Using a module
+ #
+ # module Pagination
+ # def page(number)
+ # # pagination code goes here
+ # end
+ # end
+ #
+ # scope = Model.scoped.extending(Pagination)
+ # scope.page(params[:page])
+ #
+ # You can also pass a list of modules:
+ #
+ # scope = Model.scoped.extending(Pagination, SomethingElse)
+ #
+ # === Using a block
+ #
+ # scope = Model.scoped.extending do
+ # def page(number)
+ # # pagination code goes here
+ # end
+ # end
+ # scope.page(params[:page])
+ #
+ # You can also use a block and a module list:
+ #
+ # scope = Model.scoped.extending(Pagination) do
+ # def per_page(number)
+ # # pagination code goes here
+ # end
+ # end
def extending(*modules)
modules << Module.new(&Proc.new) if block_given?
@@ -254,12 +319,12 @@ module ActiveRecord
association_joins = buckets['association_join'] || []
stashed_association_joins = buckets['stashed_join'] || []
- join_nodes = buckets['join_node'] || []
+ join_nodes = (buckets['join_node'] || []).uniq
string_joins = (buckets['string_join'] || []).map { |x|
x.strip
}.uniq
- join_list = custom_join_ast(manager, string_joins)
+ join_list = join_nodes + custom_join_ast(manager, string_joins)
join_dependency = ActiveRecord::Associations::JoinDependency.new(
@klass,
@@ -267,10 +332,6 @@ module ActiveRecord
join_list
)
- join_nodes.each do |join|
- join_dependency.alias_tracker.aliased_name_for(join.left.name.downcase)
- end
-
join_dependency.graft(*stashed_association_joins)
@implicit_readonly = true unless association_joins.empty? && stashed_association_joins.empty?
@@ -280,7 +341,6 @@ module ActiveRecord
association.join_to(manager)
end
- manager.join_sources.concat join_nodes.uniq
manager.join_sources.concat join_list
manager