From 981299e3d27e4554eebaea6a9268a9530461cc13 Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sun, 10 May 2020 06:14:29 +0900 Subject: [PATCH] Eager generate relation methods if a method is on `Kernel` Follow up of #34122. Relation method call is relying on method_missing, but if `Kernel` has the same named method (e.g. `open`, etc), it will invoke Kernel's method since method_missing is not happened. To prevent that, eager generate relation methods if a method is the same name on `Kernel`. Fixes #39195. --- activerecord/lib/active_record/scoping/named.rb | 4 ++++ activerecord/test/cases/relations_test.rb | 2 ++ activerecord/test/models/reply.rb | 4 ++++ activerecord/test/models/topic.rb | 1 + 4 files changed, 11 insertions(+) diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index 116a27e7d0..46cfb2ea21 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -198,6 +198,10 @@ module ActiveRecord end private + def singleton_method_added(name) + generate_relation_method(name) if Kernel.respond_to?(name) + end + def valid_scope_name?(name) if respond_to?(name, true) && logger logger.warn "Creating scope :#{name}. " \ diff --git a/activerecord/test/cases/relations_test.rb b/activerecord/test/cases/relations_test.rb index d8d99637c2..d5a2f896f6 100644 --- a/activerecord/test/cases/relations_test.rb +++ b/activerecord/test/cases/relations_test.rb @@ -2119,6 +2119,8 @@ class RelationTest < ActiveRecord::TestCase sub_accounts = SubAccount.all assert_equal [accounts(:signals37)], sub_accounts.open assert_equal [accounts(:signals37)], sub_accounts.available + + assert_equal [topics(:second)], topics(:first).open_replies end def test_where_with_take_memoization diff --git a/activerecord/test/models/reply.rb b/activerecord/test/models/reply.rb index f6ab9c8a8f..074a51f3df 100644 --- a/activerecord/test/models/reply.rb +++ b/activerecord/test/models/reply.rb @@ -9,6 +9,10 @@ class Reply < Topic has_many :silly_unique_replies, dependent: :destroy, foreign_key: "parent_id" scope :ordered, -> { Reply.order(:id) } + + def self.open + approved + end end class SillyReply < Topic diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index a3a0f570ae..19fb704d12 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -42,6 +42,7 @@ class Topic < ActiveRecord::Base has_many :replies, dependent: :destroy, foreign_key: "parent_id", autosave: true has_many :approved_replies, -> { approved }, class_name: "Reply", foreign_key: "parent_id", counter_cache: "replies_count" + has_many :open_replies, -> { open }, class_name: "Reply", foreign_key: "parent_id" has_many :unique_replies, dependent: :destroy, foreign_key: "parent_id" has_many :silly_unique_replies, dependent: :destroy, foreign_key: "parent_id"