I've discovered what I'm pretty confident is unexpected behavior in accepts_nested_attributes_for, and am developing a patch, but I've encountered a question about how the core team would prefer the implementation to look.
Here's the bug: when assigning to a belongs_to relationship (and I believe one-to-one, but I haven't verified yet) if you mark the association for destruction the association is not unset yet the record is deleted. This result in both unexpected behavior: the association seems to still be present in memory after the update, and in invalid data being saved (foreign key violations) because the parent record saved still has the association_id set even though the associated record has been destroyed.
Here is a test demonstrating the error and the expectations:
def test_should_destroy_an_existing_record_if_there_is_a_matching_id_and_destroy_is_truthy @ship.pirate.destroy [1, '1', true, 'true'].each do |truth| pirate = @ship.reload.create_pirate(:catchphrase => 'Arr') @ship.update_attributes(:pirate_attributes => { :id => pirate.id, :_destroy => truth }) assert_raise(ActiveRecord::RecordNotFound) { pirate.reload } end end
I've also a partial patch developed: http://pastie.org/3438962
The problem is that to trigger the record deletion, the association still needs to be there to be walked on the save call.
I have two question: 1. Does everyone agree on the expected behavior? 2. What is the best implementation route: should I maintain a hidden list/hash on each object of associations that have been unset and marked for deletion to use both at saving and if someone resets the object? Or is that capability already essentially available in the change tracking? Or something different all-together.
Something along these lines already has to be there because updating the has_many leaves the collection in memory without the marked-for- destruction records.