Don't allow destroyed object mutation after save or save! is called

Currently `object.save` will unfreeze the object, due to
`changes_applied` replaces frozen `@attributes` to new `@attributes`.

Since originally destroyed objects are not allowed to be mutated, `save`
and `save!` should not return success in that case.

Fixes #28563.
This commit is contained in:
Ryuta Kamizono 2018-01-15 04:30:37 +09:00
parent f1af27fd9d
commit 562dd0494a
3 changed files with 29 additions and 2 deletions

@ -1,3 +1,7 @@
* Don't allow destroyed object mutation after `save` or `save!` is called.
*Ryuta Kamizono*
* Take into account association conditions when deleting through records.
Fixes #18424.

@ -694,6 +694,7 @@ def _relation_for_itself
def create_or_update(*args, &block)
_raise_readonly_record_error if readonly?
return false if destroyed?
result = new_record? ? _create_record(&block) : _update_record(*args, &block)
result != false
end

@ -599,9 +599,15 @@ def test_update_all_with_non_standard_table_name
end
def test_delete_new_record
client = Client.new
client = Client.new(name: "37signals")
client.delete
assert client.frozen?
assert_not client.save
assert_raise(ActiveRecord::RecordNotSaved) { client.save! }
assert client.frozen?
assert_raise(RuntimeError) { client.name = "something else" }
end
def test_delete_record_with_associations
@ -609,13 +615,24 @@ def test_delete_record_with_associations
client.delete
assert client.frozen?
assert_kind_of Firm, client.firm
assert_not client.save
assert_raise(ActiveRecord::RecordNotSaved) { client.save! }
assert client.frozen?
assert_raise(RuntimeError) { client.name = "something else" }
end
def test_destroy_new_record
client = Client.new
client = Client.new(name: "37signals")
client.destroy
assert client.frozen?
assert_not client.save
assert_raise(ActiveRecord::RecordNotSaved) { client.save! }
assert client.frozen?
assert_raise(RuntimeError) { client.name = "something else" }
end
def test_destroy_record_with_associations
@ -623,6 +640,11 @@ def test_destroy_record_with_associations
client.destroy
assert client.frozen?
assert_kind_of Firm, client.firm
assert_not client.save
assert_raise(ActiveRecord::RecordNotSaved) { client.save! }
assert client.frozen?
assert_raise(RuntimeError) { client.name = "something else" }
end