Reputation: 81671
Given
class Post
has_many :comments
end
class Comment
belongs_to :post
end
If I want to validate that a comment always has a post, should I use
class Comment
belongs_to :post
validates :post, presence: true
end
or
class Comment
belongs_to :post
validates :post_id, presence: true
end
?
The Rails guides suggests the validates :post, presence: true
approach, saying:
If you want to be sure that an association is present, you'll need to test whether the associated object itself is present, and not the foreign key used to map the association.
One difference I can see between the two is that if you do
post = Post.new
comment = Comment.new
comment.post = post
comment.save
then validation fails if it's based on post_id
, but succeeds if it's based on post
. The latter makes more sense to me.
However, I sometimes see people in real life using the post_id
approach. Are they simply using the "wrong" approach, or is there a rationale I'm not aware of?
The Rails Style Guide doesn't have anything related to this topic.
The question Rails ActiveRecord:: Proper way for validating presence on associations? seems to be asking about how to get a project to work using the post_id
approach, but doesn't seem to explain why it's using that approach.
Rails 4: Difference between validates presence on id or association is about validation, but merely describes the different effects of the two approaches, rather than saying why post_id
should be used.
The question Rails - Validate Presence Of Association? is unrelated - it's talking about validating that a post has at least one comment, which is a different requirement to what I'm asking about.
Upvotes: 2
Views: 514
Reputation: 7779
I don't think a single case would fit all scenarios.
In the case of post
s and comment
s, I would tend to validate on the foreign_key
rather than the association. This is partly due to better performance but also testing the Comment
model would become independent of the Post
model.
For the example of Comment
and Post
, when creating a comment, I would set association (i.e. comment.post = post
or post.comments.create!
) rather than the foreign_key (i.e. comment.post_id = post.id
), so I know that the post exists (and that's why I am not validating the presence of the association). However in the unlikely case of data corruption, this will not have a significant impact on the application (just one comment wouldn't be associated with an existing post).
In other scenarios, where you need to be absolutely sure that the association is present, you could be extremely safe and validate the association (for instance a CreditCard
belongs to a User
or an Invoice
belonging to an Account
).
Upvotes: 1
Reputation: 81671
The comments section of the blog post http://railsguides.net/belongs-to-and-presence-validation-rule1/ , linked to from the answer https://stackoverflow.com/a/25808182/38765 suggests that some people validate on the post_id
just because they weren't aware of other ways of doing it:
Thanks for posting this! I've always validated on the field. I didn't even think about validating the association.
and
Amazing, thank you. That was subtle.
One person said post_id
may have better performance:
Keep in mind that validating on
:account
instead of:account_id
will incur a performance penalty, as the database has to be queried to check that the association exists.
but I tend to be wary of doing things for performance reasons.
Upvotes: 0