From d0c0e50d2b1d029969e990d75330f1a53c182c0f Mon Sep 17 00:00:00 2001 From: Wolfram Arnold Date: Sun, 28 Dec 2008 21:36:53 +0100 Subject: [PATCH] #1652 fixed - when using the :select option in named_scope don't default .empty? and .size to the .count method, without offending doc updates --- activerecord/lib/active_record/named_scope.rb | 15 ++++++++++- activerecord/test/cases/named_scope_test.rb | 31 +++++++++++++++++++++++++ activerecord/test/models/post.rb | 9 +++++++ 3 files changed, 53 insertions(+), 2 deletions(-) diff --git a/activerecord/lib/active_record/named_scope.rb b/activerecord/lib/active_record/named_scope.rb index 83043c2..caf3483 100644 --- a/activerecord/lib/active_record/named_scope.rb +++ b/activerecord/lib/active_record/named_scope.rb @@ -69,6 +69,9 @@ module ActiveRecord # end # end # + # Note that most options available with the \find method apply here too. Calling \size or \empty will resolve + # to a SELECT COUNT(*)... except when the :select option is used to explicitly override the + # SELECT statement. This is intended for special cases such as SELECT posts.*, COUNT(*) AS comment_count ... # # For testing complex named \scopes, you can examine the scoping options using the # proxy_options method on the proxy itself. @@ -137,11 +140,19 @@ module ActiveRecord end def size - @found ? @found.length : count + if @proxy_options[:select].nil? + @found ? @found.length : count + else + proxy_found.size + end end def empty? - @found ? @found.empty? : count.zero? + if @proxy_options[:select].nil? + @found ? @found.empty? : count.zero? + else + proxy_found.empty? + end end def respond_to?(method, include_private = false) diff --git a/activerecord/test/cases/named_scope_test.rb b/activerecord/test/cases/named_scope_test.rb index 64e8997..87fdca2 100644 --- a/activerecord/test/cases/named_scope_test.rb +++ b/activerecord/test/cases/named_scope_test.rb @@ -272,6 +272,37 @@ class NamedScopeTest < ActiveRecord::TestCase end end + def test_custom_select_works + expected_posts = posts(:sti_comments, :welcome, :sti_post_and_comments) + assert_queries(1) do + assert_sql(/SELECT posts\.\*, COUNT\(\*\) AS comment_count/i) do + most_commented_posts = Post.most_commented(3,0) + assert_equal expected_posts, most_commented_posts + end + end + end + + def test_empty_should_load_results_when_using_custom_select + first_expected, last_expected = posts(:sti_comments, :sti_post_and_comments) + assert_queries(1) do + assert_sql(/SELECT posts\.\*, COUNT\(\*\) AS comment_count/i) { assert !Post.most_commented(3,0).empty? } + end + end + + def test_size_should_load_results_when_using_custom_select + first_expected, last_expected = posts(:sti_comments, :sti_post_and_comments) + assert_queries(1) do + assert_sql(/SELECT posts\.\*, COUNT\(\*\) AS comment_count/i) { assert_equal 3, Post.most_commented(3,0).size } + end + end + + def test_length_should_load_results_when_using_custom_select + first_expected, last_expected = posts(:sti_comments, :sti_post_and_comments) + assert_queries(1) do + assert_sql(/SELECT posts\.\*, COUNT\(\*\) AS comment_count/i) { assert_equal 3, Post.most_commented(3,0).length } + end + end + def test_chaining_with_duplicate_joins join = "INNER JOIN comments ON comments.post_id = posts.id" post = Post.find(1) diff --git a/activerecord/test/models/post.rb b/activerecord/test/models/post.rb index e0d8be6..21abacb 100644 --- a/activerecord/test/models/post.rb +++ b/activerecord/test/models/post.rb @@ -5,6 +5,15 @@ class Post < ActiveRecord::Base :joins => 'JOIN authors ON authors.id = posts.author_id' } } + + named_scope :most_commented, + Proc.new { |limit, offset| { :select => 'posts.*, COUNT(*) AS comment_count', + :joins => :comments, + :limit => limit, + :group => 'posts.id', + :order => 'comment_count DESC, comments.id ASC', + :offset => offset + } } belongs_to :author do def greeting -- 1.5.6.3