diff --git a/activerecord/lib/active_record/relation.rb b/activerecord/lib/active_record/relation.rb index 34e643b2de19ea2d2414e8ba6c8ee9a04da76aad..38b720ffc8fea491db4d8de6590645a67085234d 100644 --- a/activerecord/lib/active_record/relation.rb +++ b/activerecord/lib/active_record/relation.rb @@ -313,6 +313,13 @@ def scoping klass.current_scope = previous end + def _exec_scope(*args, &block) # :nodoc: + @delegate_to_klass = true + instance_exec(*args, &block) || self + ensure + @delegate_to_klass = false + end + # Updates all records in the current relation with details given. This method constructs a single SQL UPDATE # statement and sends it straight to the database. It does not instantiate the involved models and it does not # trigger Active Record callbacks or validations. However, values passed to #update_all will still go through diff --git a/activerecord/lib/active_record/relation/delegation.rb b/activerecord/lib/active_record/relation/delegation.rb index 4b16b49cdf2b5ce4b83a24c202c88c7daf463d52..27450ab8b372c981bc69918a154bb60e7c4d20bc 100644 --- a/activerecord/lib/active_record/relation/delegation.rb +++ b/activerecord/lib/active_record/relation/delegation.rb @@ -82,6 +82,9 @@ def method_missing(method, *args, &block) if @klass.respond_to?(method) self.class.delegate_to_scoped_klass(method) scoping { @klass.public_send(method, *args, &block) } + elsif defined?(@delegate_to_klass) && + @delegate_to_klass && @klass.respond_to?(method, true) + @klass.send(method, *args, &block) elsif arel.respond_to?(method) ActiveSupport::Deprecation.warn \ "Delegating #{method} to arel is deprecated and will be removed in Rails 6.0." diff --git a/activerecord/lib/active_record/scoping/named.rb b/activerecord/lib/active_record/scoping/named.rb index 752655aa05f2866c21877048f7dbe9817c7f8eba..a78400158773bfb7e3bcdfe04b10bc226b83c294 100644 --- a/activerecord/lib/active_record/scoping/named.rb +++ b/activerecord/lib/active_record/scoping/named.rb @@ -183,7 +183,7 @@ def scope(name, body, &block) if body.respond_to?(:to_proc) singleton_class.send(:define_method, name) do |*args| scope = all - scope = scope.instance_exec(*args, &body) || scope + scope = scope._exec_scope(*args, &body) scope = scope.extending(extension) if extension scope end diff --git a/activerecord/test/models/topic.rb b/activerecord/test/models/topic.rb index 8cd4dc352a4eb0bb74e4467c0ce9d8b4353ba527..a924cf86ae847375ad04260b50c59acfc67cf4e1 100644 --- a/activerecord/test/models/topic.rb +++ b/activerecord/test/models/topic.rb @@ -12,9 +12,16 @@ class Topic < ActiveRecord::Base scope :scope_with_lambda, lambda { all } - scope :by_lifo, -> { where(author_name: "lifo") } + scope :by_lifo, -> { where(author_name: author_name) } scope :replied, -> { where "replies_count > 0" } + class << self + private + def author_name + "lifo" + end + end + scope "approved_as_string", -> { where(approved: true) } scope :anonymous_extension, -> {} do def one