diff --git a/activerecord/lib/active_record/relation/finder_methods.rb b/activerecord/lib/active_record/relation/finder_methods.rb index 053c62887b..3b06efa442 100644 --- a/activerecord/lib/active_record/relation/finder_methods.rb +++ b/activerecord/lib/active_record/relation/finder_methods.rb @@ -319,6 +319,21 @@ module ActiveRecord skip_query_cache_if_necessary { connection.select_rows(relation.arel, "#{name} Exists?").size == 1 } end + # Returns true if the relation contains the given record or false otherwise. + # + # No query is performed if the relation is loaded; the given record is + # compared to the records in memory. If the relation is unloaded, an + # efficient existence query is performed, as in #exists?. + def include?(record) + if loaded? + records.include?(record) + else + record.is_a?(klass) && exists?(record.id) + end + end + + alias :member? :include? + # This method is called whenever no records are found with either a single # id or multiple ids and raises an ActiveRecord::RecordNotFound exception. # diff --git a/activerecord/test/cases/finder_test.rb b/activerecord/test/cases/finder_test.rb index 980672e9bd..d33d0fb341 100644 --- a/activerecord/test/cases/finder_test.rb +++ b/activerecord/test/cases/finder_test.rb @@ -375,6 +375,84 @@ class FinderTest < ActiveRecord::TestCase end end + def test_include_on_unloaded_relation_with_match + assert_sql(/1 AS one.*LIMIT/) do + assert_equal true, Customer.where(name: "David").include?(customers(:david)) + end + end + + def test_include_on_unloaded_relation_without_match + assert_sql(/1 AS one.*LIMIT/) do + assert_equal false, Customer.where(name: "David").include?(customers(:mary)) + end + end + + def test_include_on_unloaded_relation_with_mismatched_class + topic = topics(:first) + assert Customer.exists?(topic.id) + + assert_no_queries do + assert_equal false, Customer.where(name: "David").include?(topic) + end + end + + def test_include_on_loaded_relation_with_match + customers = Customer.where(name: "David").load + david = customers(:david) + + assert_no_queries do + assert_equal true, customers.include?(david) + end + end + + def test_include_on_loaded_relation_without_match + customers = Customer.where(name: "David").load + mary = customers(:mary) + + assert_no_queries do + assert_equal false, customers.include?(mary) + end + end + + def test_member_on_unloaded_relation_with_match + assert_sql(/1 AS one.*LIMIT/) do + assert_equal true, Customer.where(name: "David").member?(customers(:david)) + end + end + + def test_member_on_unloaded_relation_without_match + assert_sql(/1 AS one.*LIMIT/) do + assert_equal false, Customer.where(name: "David").member?(customers(:mary)) + end + end + + def test_member_on_unloaded_relation_with_mismatched_class + topic = topics(:first) + assert Customer.exists?(topic.id) + + assert_no_queries do + assert_equal false, Customer.where(name: "David").member?(topic) + end + end + + def test_member_on_loaded_relation_with_match + customers = Customer.where(name: "David").load + david = customers(:david) + + assert_no_queries do + assert_equal true, customers.member?(david) + end + end + + def test_member_on_loaded_relation_without_match + customers = Customer.where(name: "David").load + mary = customers(:mary) + + assert_no_queries do + assert_equal false, customers.member?(mary) + end + end + def test_find_by_array_of_one_id assert_kind_of(Array, Topic.find([ 1 ])) assert_equal(1, Topic.find([ 1 ]).length) diff --git a/activerecord/test/cases/relation/delegation_test.rb b/activerecord/test/cases/relation/delegation_test.rb index fd78572f85..83d12e6dd5 100644 --- a/activerecord/test/cases/relation/delegation_test.rb +++ b/activerecord/test/cases/relation/delegation_test.rb @@ -48,7 +48,7 @@ module ActiveRecord QUERYING_METHODS = ActiveRecord::Batches.public_instance_methods(false) + ActiveRecord::Calculations.public_instance_methods(false) + - ActiveRecord::FinderMethods.public_instance_methods(false) - [:raise_record_not_found_exception!] + + ActiveRecord::FinderMethods.public_instance_methods(false) - [:include?, :member?, :raise_record_not_found_exception!] + ActiveRecord::SpawnMethods.public_instance_methods(false) - [:spawn, :merge!] + ActiveRecord::QueryMethods.public_instance_methods(false).reject { |method| method.end_with?("=", "!", "value", "values", "clause")