diff --git a/activerecord/lib/active_record/association_relation.rb b/activerecord/lib/active_record/association_relation.rb index 91c2df8465afc..fd7b4aaf9eaae 100644 --- a/activerecord/lib/active_record/association_relation.rb +++ b/activerecord/lib/active_record/association_relation.rb @@ -17,23 +17,23 @@ def ==(other) def build(attributes = nil, &block) block = _deprecated_scope_block("new", &block) - @association.enable_scoping do - scoping { @association.build(attributes, &block) } + @association.scoping(self) do + @association.build(attributes, &block) end end alias new build def create(attributes = nil, &block) block = _deprecated_scope_block("create", &block) - @association.enable_scoping do - scoping { @association.create(attributes, &block) } + @association.scoping(self) do + @association.create(attributes, &block) end end def create!(attributes = nil, &block) block = _deprecated_scope_block("create!", &block) - @association.enable_scoping do - scoping { @association.create!(attributes, &block) } + @association.scoping(self) do + @association.create!(attributes, &block) end end diff --git a/activerecord/lib/active_record/associations/association.rb b/activerecord/lib/active_record/associations/association.rb index d1334650c6575..5d68d6d188b3b 100644 --- a/activerecord/lib/active_record/associations/association.rb +++ b/activerecord/lib/active_record/associations/association.rb @@ -41,7 +41,7 @@ def initialize(owner, reflection) reflection.check_validity! @owner, @reflection = owner, reflection - @enable_scoping = false + @_scope = nil reset reset_scope @@ -98,7 +98,7 @@ def target=(target) end def scope - target_scope.merge!(association_scope) + @_scope&.spawn || target_scope.merge!(association_scope) end def reset_scope @@ -198,11 +198,11 @@ def create!(attributes = nil, &block) _create_record(attributes, true, &block) end - def enable_scoping - @enable_scoping = true - yield + def scoping(relation, &block) + @_scope = relation + relation.scoping(&block) ensure - @enable_scoping = false + @_scope = nil end private @@ -235,11 +235,7 @@ def association_scope # Can be overridden (i.e. in ThroughAssociation) to merge in other scopes (i.e. the # through association's scope) def target_scope - AssociationRelation.create(klass, self).merge!(scope_for_association) - end - - def scope_for_association - @enable_scoping ? klass.all : klass.scope_for_association + AssociationRelation.create(klass, self).merge!(klass.scope_for_association) end def scope_for_create diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index 8e6008027b097..cb3985a45cbd3 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -254,6 +254,15 @@ def test_build_and_create_from_association_should_respect_unscope_over_default_s bulb = car.bulbs.unscope(where: :name).create! assert_nil bulb.name + + bulb = car.awesome_bulbs.unscope(where: :frickinawesome).build + assert_equal false, bulb.frickinawesome + + bulb = car.awesome_bulbs.unscope(where: :frickinawesome).create + assert_equal false, bulb.frickinawesome + + bulb = car.awesome_bulbs.unscope(where: :frickinawesome).create! + assert_equal false, bulb.frickinawesome end def test_build_from_association_should_respect_scope diff --git a/activerecord/test/cases/associations/has_many_through_associations_test.rb b/activerecord/test/cases/associations/has_many_through_associations_test.rb index 6faa9664f7c62..9d05ee0820779 100644 --- a/activerecord/test/cases/associations/has_many_through_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_through_associations_test.rb @@ -688,8 +688,10 @@ def test_associate_with_create def test_through_record_is_built_when_created_with_where assert_difference("posts(:thinking).readers.count", 1) do - posts(:thinking).people.where(first_name: "Jeb").create + posts(:thinking).people.where(readers: { skimmer: true }).create(first_name: "Jeb") end + reader = posts(:thinking).readers.last + assert_equal true, reader.skimmer end def test_associate_with_create_and_no_options