diff options
author | Sean Griffin <sean@thoughtbot.com> | 2015-07-24 09:13:20 -0600 |
---|---|---|
committer | Sean Griffin <sean@thoughtbot.com> | 2015-07-24 09:13:20 -0600 |
commit | d937a1175f10586b892842348c1d6ecaa47aad2e (patch) | |
tree | 6ecb43ac1164c564d60ed30265e81be418ca6977 /activerecord/test/cases | |
parent | cc214cff7eb36e907df253542c8548f8bef230cb (diff) | |
download | rails-d937a1175f10586b892842348c1d6ecaa47aad2e.tar.gz rails-d937a1175f10586b892842348c1d6ecaa47aad2e.tar.bz2 rails-d937a1175f10586b892842348c1d6ecaa47aad2e.zip |
`destroy` shouldn't raise when child associations fail to save
Deep down in the association internals, we're calling `destroy!` rather
than `destroy` when handling things like `dependent` or autosave
association callbacks. Unfortunately, due to the structure of the code
(e.g. it uses callbacks for everything), it's nearly impossible to pass
whether to call `destroy` or `destroy!` down to where we actually need
it.
As such, we have to do some legwork to handle this. Since the callbacks
are what actually raise the exception, we need to rescue it in
`ActiveRecord::Callbacks`, rather than `ActiveRecord::Persistence` where
it matters. (As an aside, if this code wasn't so callback heavy, it
would handling this would likely be as simple as changing `destroy` to
call `destroy!` instead of the other way around).
Since we don't want to lose the exception when `destroy!` is called (in
particular, we don't want the value of the `record` field to change to
the parent class), we have to do some additional legwork to hold onto it
where we can use it.
Again, all of this is ugly and there is definitely a better way to do
this. However, barring a much more significant re-architecting for what
I consider to be a reletively minor improvement, I'm willing to take
this small hit to the flow of this code (begrudgingly).
Diffstat (limited to 'activerecord/test/cases')
-rw-r--r-- | activerecord/test/cases/associations/has_many_associations_test.rb | 30 |
1 files changed, 30 insertions, 0 deletions
diff --git a/activerecord/test/cases/associations/has_many_associations_test.rb b/activerecord/test/cases/associations/has_many_associations_test.rb index c2ef59d0f7..21e2ee3b11 100644 --- a/activerecord/test/cases/associations/has_many_associations_test.rb +++ b/activerecord/test/cases/associations/has_many_associations_test.rb @@ -2278,4 +2278,34 @@ class HasManyAssociationsTest < ActiveRecord::TestCase assert_deprecated { company.clients_of_firm(true) } end + + class AuthorWithErrorDestroyingAssociation < ActiveRecord::Base + self.table_name = "authors" + has_many :posts_with_error_destroying, + class_name: "PostWithErrorDestroying", + foreign_key: :author_id, + dependent: :destroy + end + + class PostWithErrorDestroying < ActiveRecord::Base + self.table_name = "posts" + self.inheritance_column = nil + before_destroy -> { throw :abort } + end + + def test_destroy_does_not_raise_when_association_errors_on_destroy + assert_no_difference "AuthorWithErrorDestroyingAssociation.count" do + author = AuthorWithErrorDestroyingAssociation.first + + assert_not author.destroy + end + end + + def test_destroy_with_bang_bubbles_errors_from_associations + error = assert_raises ActiveRecord::RecordNotDestroyed do + AuthorWithErrorDestroyingAssociation.first.destroy! + end + + assert_instance_of PostWithErrorDestroying, error.record + end end |