Skip to content

Commit

Permalink
Implement #many? for NamedScope and AssociationCollection using #size [
Browse files Browse the repository at this point in the history
…#1500 state:resolved]

Signed-off-by: Pratik Naik <pratiknaik@gmail.com>
  • Loading branch information
chrisk authored and lifo committed May 17, 2009
1 parent 11bac70 commit 4e8c36a
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 1 deletion.
2 changes: 2 additions & 0 deletions activerecord/CHANGELOG
@@ -1,5 +1,7 @@
*Edge*

* Implement #many? for NamedScope and AssociationCollection using #size. #1500 [Chris Kampmeier]

* Added :touch option to belongs_to associations that will touch the parent record when the current record is saved or destroyed [DHH]

* Added ActiveRecord::Base#touch to update the updated_at/on attributes (or another specified timestamp) with the current time [DHH]
Expand Down
Expand Up @@ -302,6 +302,15 @@ def any?
end
end

# Returns true if the collection has more than 1 record. Equivalent to collection.size > 1.
def many?
if block_given?
method_missing(:many?) { |*block_args| yield(*block_args) }
else
size > 1
end
end

def uniq(collection = self)
seen = Set.new
collection.inject([]) do |kept, record|
Expand Down
11 changes: 10 additions & 1 deletion activerecord/lib/active_record/named_scope.rb
Expand Up @@ -109,7 +109,7 @@ def named_scope(name, options = {}, &block)

class Scope
attr_reader :proxy_scope, :proxy_options, :current_scoped_methods_when_defined
NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? respond_to?).to_set
NON_DELEGATE_METHODS = %w(nil? send object_id class extend find size count sum average maximum minimum paginate first last empty? any? many? respond_to?).to_set
[].methods.each do |m|
unless m =~ /^__/ || NON_DELEGATE_METHODS.include?(m.to_s)
delegate m, :to => :proxy_found
Expand Down Expand Up @@ -168,6 +168,15 @@ def any?
end
end

# Returns true if the named scope has more than 1 matching record.
def many?
if block_given?
proxy_found.many? { |*block_args| yield(*block_args) }
else
size > 1
end
end

protected
def proxy_found
@found || load_found
Expand Down
39 changes: 39 additions & 0 deletions activerecord/test/cases/associations/has_many_associations_test.rb
Expand Up @@ -1023,6 +1023,45 @@ def test_calling_first_or_last_with_integer_on_association_should_load_associati
assert firm.clients.loaded?
end

def test_calling_many_should_count_instead_of_loading_association
firm = companies(:first_firm)
assert_queries(1) do
firm.clients.many? # use count query
end
assert !firm.clients.loaded?
end

def test_calling_many_on_loaded_association_should_not_use_query
firm = companies(:first_firm)
firm.clients.collect # force load
assert_no_queries { assert firm.clients.many? }
end

def test_calling_many_should_defer_to_collection_if_using_a_block
firm = companies(:first_firm)
assert_queries(1) do
firm.clients.expects(:size).never
firm.clients.many? { true }
end
assert firm.clients.loaded?
end

def test_calling_many_should_return_false_if_none_or_one
firm = companies(:another_firm)
assert !firm.clients_like_ms.many?
assert_equal 0, firm.clients_like_ms.size

firm = companies(:first_firm)
assert !firm.limited_clients.many?
assert_equal 1, firm.limited_clients.size
end

def test_calling_many_should_return_true_if_more_than_one
firm = companies(:first_firm)
assert firm.clients.many?
assert_equal 2, firm.clients.size
end

def test_joins_with_namespaced_model_should_use_correct_type
old = ActiveRecord::Base.store_full_sti_class
ActiveRecord::Base.store_full_sti_class = true
Expand Down
34 changes: 34 additions & 0 deletions activerecord/test/cases/named_scope_test.rb
Expand Up @@ -235,6 +235,40 @@ def test_any_should_not_fire_query_if_named_scope_loaded
assert_no_queries { assert topics.any? }
end

def test_many_should_not_load_results
topics = Topic.base
assert_queries(2) do
topics.many? # use count query
topics.collect # force load
topics.many? # use loaded (no query)
end
end

def test_many_should_call_proxy_found_if_using_a_block
topics = Topic.base
assert_queries(1) do
topics.expects(:size).never
topics.many? { true }
end
end

def test_many_should_not_fire_query_if_named_scope_loaded
topics = Topic.base
topics.collect # force load
assert_no_queries { assert topics.many? }
end

def test_many_should_return_false_if_none_or_one
topics = Topic.base.scoped(:conditions => {:id => 0})
assert !topics.many?
topics = Topic.base.scoped(:conditions => {:id => 1})
assert !topics.many?
end

def test_many_should_return_true_if_more_than_one
assert Topic.base.many?
end

def test_should_build_with_proxy_options
topic = Topic.approved.build({})
assert topic.approved
Expand Down

0 comments on commit 4e8c36a

Please sign in to comment.