From f64b5fb942b6fbded3cc9ecbe0691604cbc7430e Mon Sep 17 00:00:00 2001 From: Ryuta Kamizono Date: Sat, 21 Mar 2020 23:10:34 +0900 Subject: [PATCH] Allow extra scoping in callbacks when create on association relation #37523 has a regression that ignore extra scoping in callbacks when create on association relation. It should respect `klass.current_scope` even when create on association relation to allow extra scoping in callbacks. Fixes #38741. --- .../lib/active_record/association_relation.rb | 12 +++--------- .../lib/active_record/associations/association.rb | 14 +++++--------- .../associations/has_many_associations_test.rb | 12 ++++++++++++ activerecord/test/models/bulb.rb | 9 ++++++++- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb index fd7b4aaf9e..224a8a368c 100644 --- a/activerecord/lib/active_record/association_relation.rb +++ b/activerecord/lib/active_record/association_relation.rb @@ -17,24 +17,18 @@ module ActiveRecord def build(attributes = nil, &block) block = _deprecated_scope_block("new", &block) - @association.scoping(self) do - @association.build(attributes, &block) - end + scoping { @association.build(attributes, &block) } end alias new build def create(attributes = nil, &block) block = _deprecated_scope_block("create", &block) - @association.scoping(self) do - @association.create(attributes, &block) - end + scoping { @association.create(attributes, &block) } end def create!(attributes = nil, &block) block = _deprecated_scope_block("create!", &block) - @association.scoping(self) do - @association.create!(attributes, &block) - end + scoping { @association.create!(attributes, &block) } end private diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index 50d586d290..537d61900e 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -41,7 +41,6 @@ module ActiveRecord reflection.check_validity! @owner, @reflection = owner, reflection - @_scope = nil reset reset_scope @@ -98,7 +97,11 @@ module ActiveRecord end def scope - @_scope&.spawn || target_scope.merge!(association_scope) + if (scope = klass.current_scope) && scope.try(:proxy_association) == self + scope.spawn + else + target_scope.merge!(association_scope) + end end def reset_scope @@ -198,13 +201,6 @@ module ActiveRecord _create_record(attributes, true, &block) end - def scoping(relation, &block) - @_scope = relation - relation.scoping(&block) - ensure - @_scope = nil - end - private def find_target if owner.strict_loading? diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index ff471daec5..57b18b8d21 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -224,6 +224,18 @@ class HasManyAssociationsTest < ActiveRecord::TestCase def test_build_and_create_from_association_should_respect_passed_attributes_over_default_scope car = Car.create(name: "honda") + bulb = car.bulbs.where(name: "exotic").build + assert_equal "exotic", bulb.name + assert_nil bulb.count_after_create + + bulb = car.bulbs.where(name: "exotic").create + assert_equal "exotic", bulb.name + assert_equal 1, bulb.count_after_create + + bulb = car.bulbs.where(name: "exotic").create! + assert_equal "exotic", bulb.name + assert_equal 2, bulb.count_after_create + bulb = car.bulbs.build(name: "exotic") assert_equal "exotic", bulb.name diff --git a/activerecord/test/models/bulb.rb b/activerecord/test/models/bulb.rb index 5e97772bfe..3c20b8c211 100644 --- a/activerecord/test/models/bulb.rb +++ b/activerecord/test/models/bulb.rb @@ -5,7 +5,7 @@ class Bulb < ActiveRecord::Base belongs_to :car, touch: true scope :awesome, -> { where(frickinawesome: true) } - attr_reader :scope_after_initialize, :attributes_after_initialize + attr_reader :scope_after_initialize, :attributes_after_initialize, :count_after_create after_initialize :record_scope_after_initialize def record_scope_after_initialize @@ -17,6 +17,13 @@ class Bulb < ActiveRecord::Base @attributes_after_initialize = attributes.dup end + after_create :record_count_after_create + def record_count_after_create + @count_after_create = Bulb.unscoped do + car&.bulbs&.count + end + end + def color=(color) self[:color] = color.upcase + "!" end