Did You Know? Validating belongs_to Relationships
This is one of those things that is probably obvious to some, and just not known to some. I was in that latter description up until a few minutes ago. It’s that you can easily validate any belongs_to relationship by simply using valdiates_presence_of
.
class Comment < ActiveRecord::Base belongs_to :article validates_presence_of :article end
If you instantiate a new Comment, and don’t assign an Article to the comment instance, the record won’t save. I have to say, that seemed pretty obvious. But there is another interesting piece to this. Say I passed the article_id in the params and tried to assign that to our instance
comment = Comment.new comment.article_id = params[:article_id]
If article_id corresponds to a real article in our database, then comment.article will have be assigned an Article with that id. Now if params[:article_id] happens to be some id which doesn’t exist, like 99999999999, then comment.article will be nil and thus the record fails validation. This means that you don’t have to test for the existence of the Article against your records because rails will do this for you when it checks to see if comment.article is nil or not.
November 12th, 2008 at 3:57 am #Eric
Thank you! I’m learning RoR and found this very useful. For some reason, it can be difficult finding this kind of information.
February 11th, 2009 at 11:53 am #Raoul Duke
@for some reason
AMEN!
June 24th, 2010 at 7:38 pm #BBG
Great post. I really appreciate the information. You are doing a great job communicating your message. Keep up the good work.
July 27th, 2010 at 7:08 pm #Saint
This will only work in cases where the Article association has not been pre-loaded. E.g.
comment = Comment.new
comment.article_id = Article.first.id
c.valid? #returns true
comment.article_id == comment.article.id #returns true
#So far so good
comment.article_id = nil
c.valid? #Still returns true because the article association is not reloaded for the validation
comment.article_id == comment.article.id #returns false. At this point the comment is valid and a save will succeed but the article_id saved in the db will be null. Perhaps the only way to handle this is to override the article_id= method and force Rails to reload the association:
def article_id=(new_id)
result = super(new_id)
article(true)
result
end
Frankly Rails should be handling all for us this anyway.