提交 ed186ace 编写于 作者: R Ryuta Kamizono

Merge pull request #37658 from rails/fix-collection-association-callback

Fix collection callbacks not terminating when abort is thrown
上级 97fcbfe6
......@@ -378,7 +378,9 @@ def delete_or_destroy(records, method)
end
def remove_records(existing_records, records, method)
records.each { |record| callback(:before_remove, record) }
catch(:abort) do
records.each { |record| callback(:before_remove, record) }
end || return
delete_records(existing_records, method) if existing_records.any?
@target -= records
......@@ -434,7 +436,9 @@ def concat_records(records, raise = false)
end
def replace_on_target(record, index, skip_callbacks)
callback(:before_add, record) unless skip_callbacks
catch(:abort) do
callback(:before_add, record)
end || return unless skip_callbacks
set_inverse_instance(record)
......
......@@ -62,6 +62,23 @@ def test_multiple_callbacks
"after_adding#{@thinking.id}", "after_adding_proc#{@thinking.id}"], @david.post_log
end
def test_has_many_callbacks_halt_execution_when_abort_is_trown_when_adding_to_association
author = Author.create!(name: "Roger")
post = Post.create!(title: "hello", body: "abc")
author.posts_with_thrown_callbacks << post
assert_empty(author.posts_with_callbacks)
end
def test_has_many_callbacks_halt_execution_when_abort_is_trown_when_removing_from_association
author = Author.create!(name: "Roger")
post = Post.create!(title: "hello", body: "abc", author: author)
assert_equal(1, author.posts_with_thrown_callbacks.size)
author.posts_with_thrown_callbacks.destroy(post.id)
assert_equal(1, author.posts_with_thrown_callbacks.size)
end
def test_has_many_callbacks_with_create
morten = Author.create name: "Morten"
post = morten.posts_with_proc_callbacks.create! title: "Hello", body: "How are you doing?"
......
......@@ -71,6 +71,10 @@ def ratings
after_add: :log_after_adding,
before_remove: :log_before_removing,
after_remove: :log_after_removing
has_many :posts_with_thrown_callbacks, class_name: "Post", before_add: :throw_abort,
after_add: :ensure_not_called,
before_remove: :throw_abort,
after_remove: :ensure_not_called
has_many :posts_with_proc_callbacks, class_name: "Post",
before_add: Proc.new { |o, r| o.post_log << "before_adding#{r.id || '<new>'}" },
after_add: Proc.new { |o, r| o.post_log << "after_adding#{r.id || '<new>'}" },
......@@ -185,6 +189,14 @@ def social
validates_presence_of :name
private
def throw_abort(_)
throw(:abort)
end
def ensure_not_called(_)
raise
end
def log_before_adding(object)
@post_log << "before_adding#{object.id || '<new>'}"
end
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册