rails: Building a has_one association fails on save if target has a validation on foreign_key
Hello,
A gist for the busy can be found here
Assuming the following:
class Post < ActiveRecord::Base
has_one :comment
end
class Comment < ActiveRecord::Base
validates_presence_of :post_id
belongs_to :post
end
This script:
post = Post.create!
post.comment = Comment.create!({post_id: post.id})
post.build_comment
will fail because build
is trying to delete the original comment, but that one can’t
be deleted because there is a validation on post_id
.
This is because prior to deleting, the foreign key of the target association is set to nil and a save operation is performed on the target. I am not sure why this is done. Per my use case, I no longer need the associated target prior to building a new one, and therefore a destroy call should succeed without the need to save, ideally, but not setting the foreign_key
to nil
will also work.
Furthermore, this could be (accidentally, I should say) mitigated by passing a dependent: :destroy
to the Post
model. In other words, this:
class Post < ActiveRecord::Base
has_one :comment, dependent: :destroy
end
will make the build operation successful. There is nothing in the semantics of dependent: :destroy
that should affect a target association without affecting the owner, but in this case it does.
The issue is with this particular method, which is called prior to a saving the target association (in our case, the comment instance).
I can submit a PR if this is a clear issue for everyone.
About this issue
- Original URL
- State: open
- Created 10 years ago
- Reactions: 5
- Comments: 17 (13 by maintainers)
This is still reproducible and raises the following error:
I ran into this too and it had me wondering what was going on. Surely if it’s a has_one association and the associated class has a uniqueness validator on the foreign key then logically a second attempt at creating the association should just fail the foreign key uniqueness validation instead of nullifying the foreign key?
@why-el Please try the following. This should make it work