Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow extra scoping in callbacks when create on association relation #38916

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 3 additions & 9 deletions activerecord/lib/active_record/association_relation.rb
Expand Up @@ -17,24 +17,18 @@ def ==(other)

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
Expand Down
14 changes: 5 additions & 9 deletions activerecord/lib/active_record/associations/association.rb
Expand Up @@ -41,7 +41,6 @@ def initialize(owner, reflection)
reflection.check_validity!

@owner, @reflection = owner, reflection
@_scope = nil

reset
reset_scope
Expand Down Expand Up @@ -98,7 +97,11 @@ def target=(target)
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
Expand Down Expand Up @@ -198,13 +201,6 @@ def create!(attributes = nil, &block)
_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?
Expand Down
12 changes: 12 additions & 0 deletions activerecord/test/cases/associations/has_many_associations_test.rb
Expand Up @@ -224,6 +224,18 @@ def test_create_from_association_should_respect_default_scope
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

Expand Down
9 changes: 8 additions & 1 deletion activerecord/test/models/bulb.rb
Expand Up @@ -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
Expand All @@ -17,6 +17,13 @@ def record_attributes_after_initialize
@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
Expand Down