aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activerecord/lib/active_record.rb1
-rwxr-xr-xactiverecord/lib/active_record/associations.rb17
-rwxr-xr-xactiverecord/lib/active_record/base.rb56
-rw-r--r--activerecord/lib/active_record/relation.rb39
-rwxr-xr-xactiverecord/test/cases/base_test.rb2
-rw-r--r--activerecord/test/cases/finder_test.rb4
-rw-r--r--activerecord/test/cases/method_scoping_test.rb4
-rw-r--r--activerecord/test/cases/named_scope_test.rb8
8 files changed, 77 insertions, 54 deletions
diff --git a/activerecord/lib/active_record.rb b/activerecord/lib/active_record.rb
index 3b8b9826fe..009071e1d4 100644
--- a/activerecord/lib/active_record.rb
+++ b/activerecord/lib/active_record.rb
@@ -52,6 +52,7 @@ module ActiveRecord
autoload :Associations, 'active_record/associations'
autoload :AttributeMethods, 'active_record/attribute_methods'
autoload :AutosaveAssociation, 'active_record/autosave_association'
+ autoload :Relation, 'active_record/relation'
autoload :Base, 'active_record/base'
autoload :Batches, 'active_record/batches'
autoload :Calculations, 'active_record/calculations'
diff --git a/activerecord/lib/active_record/associations.rb b/activerecord/lib/active_record/associations.rb
index 47f97718eb..a0aeff68b6 100755
--- a/activerecord/lib/active_record/associations.rb
+++ b/activerecord/lib/active_record/associations.rb
@@ -1602,16 +1602,17 @@ module ActiveRecord
conditions = construct_conditions(options[:conditions], scope) || ''
conditions << construct_limited_ids_condition(conditions, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
- arel_table((scope && scope[:from]) || options[:from])
- join(joins)
- where(conditions)
- project(column_aliases(join_dependency))
- group(construct_group(options[:group], options[:having], scope))
- order(construct_order(options[:order], scope))
+ relation = arel_table((scope && scope[:from]) || options[:from]).
+ join(joins).
+ where(conditions).
+ project(column_aliases(join_dependency)).
+ group(construct_group(options[:group], options[:having], scope)).
+ order(construct_order(options[:order], scope)
+ )
- take(construct_limit(options[:limit], scope)) if using_limitable_reflections?(join_dependency.reflections)
+ relation = relation.take(construct_limit(options[:limit], scope)) if using_limitable_reflections?(join_dependency.reflections)
- return sanitize_sql(arel_relation.to_sql)
+ return sanitize_sql(relation.to_sql)
end
def construct_limited_ids_condition(where, options, join_dependency)
diff --git a/activerecord/lib/active_record/base.rb b/activerecord/lib/active_record/base.rb
index 85f7cbfad2..718f7ea37b 100755
--- a/activerecord/lib/active_record/base.rb
+++ b/activerecord/lib/active_record/base.rb
@@ -663,7 +663,8 @@ module ActiveRecord #:nodoc:
# This is an alias for find(:all). You can pass in all the same arguments to this method as you can
# to find(:all)
def all(*args)
- find(:all, *args)
+ relation = arel_table
+ construct_finder_arel(*args)
end
# Executes a custom SQL query against your database and returns all the results. The results will
@@ -861,22 +862,21 @@ module ActiveRecord #:nodoc:
def update_all(updates, conditions = nil, options = {})
scope = scope(:find)
- arel_table
+ relation = arel_table.relation
if conditions = construct_conditions(conditions, scope)
- where(Arel::SqlLiteral.new(conditions))
+ relation = relation.where(Arel::SqlLiteral.new(conditions))
end
if options.has_key?(:limit) || (scope && scope[:limit])
# Only take order from scope if limit is also provided by scope, this
# is useful for updating a has_many association with a limit.
- order(construct_order(options[:order], scope))
- take(construct_limit(options[:limit], scope))
+ relation = relation.order(construct_order(options[:order], scope)).take(construct_limit(options[:limit], scope))
else
- order(construct_order(options[:order], nil))
+ relation = relation.order(construct_order(options[:order], nil))
end
- arel_relation.update(sanitize_sql_for_assignment(updates))
+ relation.update(sanitize_sql_for_assignment(updates))
end
# Destroys the records matching +conditions+ by instantiating each
@@ -1536,25 +1536,7 @@ module ActiveRecord #:nodoc:
def arel_table(table = nil)
table = table_name if table.blank?
- self.arel_relation = Arel::Table.new(table)
- end
-
- def arel_relation
- Thread.current[:"#{self}_arel_relation"] ||= Arel::Table.new(table_name)
- end
-
- def arel_relation=(relation)
- Thread.current[:"#{self}_arel_relation"] = relation
- end
-
- CLAUSES_METHODS = ["where", "join", "project", "group", "order", "take", "skip"].freeze
-
- for clause in CLAUSES_METHODS
- class_eval %{
- def #{clause}(_#{clause})
- self.arel_relation = self.arel_relation.#{clause}(_#{clause}) if _#{clause}
- end
- }
+ Relation.new(self, table)
end
private
@@ -1736,21 +1718,21 @@ module ActiveRecord #:nodoc:
end
end
- def construct_finder_arel(options, scope = scope(:find))
+ def construct_finder_arel(options = {}, scope = scope(:find))
# TODO add lock to Arel
- arel_table(options[:from])
- join(construct_join(options[:joins], scope))
- where(construct_conditions(options[:conditions], scope))
- project(options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins])))
- group(construct_group(options[:group], options[:having], scope))
- order(construct_order(options[:order], scope))
- take(construct_limit(options[:limit], scope))
- skip(construct_offset(options[:offset], scope))
- arel_relation
+ arel_table(options[:from]).
+ join(construct_join(options[:joins], scope)).
+ where(construct_conditions(options[:conditions], scope)).
+ project(options[:select] || (scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))).
+ group(construct_group(options[:group], options[:having], scope)).
+ order(construct_order(options[:order], scope)).
+ take(construct_limit(options[:limit], scope)).
+ skip(construct_offset(options[:offset], scope)
+ )
end
def construct_finder_sql(options, scope = scope(:find))
- construct_finder_arel(options, scope).to_sql
+ construct_finder_arel(options, scope).relation.to_sql
end
def construct_join(joins, scope)
diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb
new file mode 100644
index 0000000000..36e8d98298
--- /dev/null
+++ b/activerecord/lib/active_record/relation.rb
@@ -0,0 +1,39 @@
+module ActiveRecord
+ class Relation
+ delegate :delete, :to_sql, :to => :relation
+ CLAUSES_METHODS = ["where", "join", "project", "group", "order", "take", "skip"].freeze
+ attr_reader :relation, :klass
+
+ def initialize(klass, table = nil)
+ @klass = klass
+ @relation = Arel::Table.new(table || @klass.table_name)
+ end
+
+ def to_a
+ @klass.find_by_sql(@relation.to_sql)
+ end
+
+ def first
+ @relation = @relation.take(1)
+ to_a.first
+ end
+
+ for clause in CLAUSES_METHODS
+ class_eval %{
+ def #{clause}(_#{clause})
+ @relation = @relation.#{clause}(_#{clause}) if _#{clause}
+ self
+ end
+ }
+ end
+
+ private
+ def method_missing(method, *args, &block)
+ if @relation.respond_to?(method)
+ @relation.send(method, *args, &block)
+ elsif Array.instance_methods.include?(method.to_s)
+ to_a.send(method, *args, &block)
+ end
+ end
+ end
+end
diff --git a/activerecord/test/cases/base_test.rb b/activerecord/test/cases/base_test.rb
index e47f898485..3143ec2850 100755
--- a/activerecord/test/cases/base_test.rb
+++ b/activerecord/test/cases/base_test.rb
@@ -1784,7 +1784,7 @@ class BasicsTest < ActiveRecord::TestCase
end
def test_all_with_conditions
- assert_equal Developer.find(:all, :order => 'id desc'), Developer.all(:order => 'id desc')
+ assert_equal Developer.find(:all, :order => 'id desc'), Developer.all.order('id desc').to_a
end
def test_find_ordered_last
diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb
index d8f5695a0f..f8c8d3648a 100644
--- a/activerecord/test/cases/finder_test.rb
+++ b/activerecord/test/cases/finder_test.rb
@@ -1072,10 +1072,10 @@ class FinderTest < ActiveRecord::TestCase
end
def test_finder_with_scoped_from
- all_topics = Topic.all
+ all_topics = Topic.find(:all)
Topic.with_scope(:find => { :from => 'fake_topics' }) do
- assert_equal all_topics, Topic.all(:from => 'topics')
+ assert_equal all_topics, Topic.all(:from => 'topics').to_a
end
end
diff --git a/activerecord/test/cases/method_scoping_test.rb b/activerecord/test/cases/method_scoping_test.rb
index bea5c5fb76..d4e63ce2fd 100644
--- a/activerecord/test/cases/method_scoping_test.rb
+++ b/activerecord/test/cases/method_scoping_test.rb
@@ -592,12 +592,12 @@ class DefaultScopingTest < ActiveRecord::TestCase
end
def test_default_scope_with_conditions_string
- assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.map(&:id).sort
+ assert_equal Developer.find_all_by_name('David').map(&:id).sort, DeveloperCalledDavid.all.to_a.map(&:id).sort
assert_equal nil, DeveloperCalledDavid.create!.name
end
def test_default_scope_with_conditions_hash
- assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.map(&:id).sort
+ assert_equal Developer.find_all_by_name('Jamis').map(&:id).sort, DeveloperCalledJamis.all.to_a.map(&:id).sort
assert_equal 'Jamis', DeveloperCalledJamis.create!.name
end
diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb
index 92fe48cb5a..10daff5d65 100644
--- a/activerecord/test/cases/named_scope_test.rb
+++ b/activerecord/test/cases/named_scope_test.rb
@@ -344,14 +344,14 @@ class NamedScopeTest < ActiveRecord::TestCase
def test_chaining_should_use_latest_conditions_when_searching
# Normal hash conditions
- assert_equal Topic.all(:conditions => {:approved => true}), Topic.rejected.approved.all
- assert_equal Topic.all(:conditions => {:approved => false}), Topic.approved.rejected.all
+ assert_equal Topic.all(:conditions => {:approved => true}).to_a, Topic.rejected.approved.all.to_a
+ assert_equal Topic.all(:conditions => {:approved => false}).to_a, Topic.approved.rejected.all.to_a
# Nested hash conditions with same keys
- assert_equal [posts(:sti_comments)], Post.with_special_comments.with_very_special_comments.all
+ assert_equal [posts(:sti_comments)], Post.with_special_comments.with_very_special_comments.all.to_a
# Nested hash conditions with different keys
- assert_equal [posts(:sti_comments)], Post.with_special_comments.with_post(4).all.uniq
+ assert_equal [posts(:sti_comments)], Post.with_special_comments.with_post(4).all.to_a.uniq
end
def test_methods_invoked_within_scopes_should_respect_scope