18

I have a Category and a Post model, with each Post belonging to a Category. Before creating or updating a post, I need to check that the category selected exists. What's the best way to validate this information?

At the moment, I'm doing a find in the controller to ensure that the category exists. Is it possible to put these kinds of validations in the model?

7 Answers 7

21

http://blog.hasmanythrough.com/2007/7/14/validate-your-existence

class Post < ActiveRecord::Base belongs_to :category validates_presence_of :category end 

-OR-

class Post < ActiveRecord::Base belongs_to :category validates :category, presence: true end 

Rails versions prior to 3.2:

class Post < ActiveRecord::Base belongs_to :category validates_existence_of :category end 
Sign up to request clarification or add additional context in comments.

5 Comments

Will this work if the category is scoped? Say that the category belongs to a Blog. The user should only be allowed to select categories belonging to to the blog.
@Homar Not sure about scoping, if the belongs_to association includes this restriction, I'd assume it would work.
this was renamed to validates_presence_of in newer rails versions
This doesn't give a very user-friendly error message. Any ideas how to fix that?
@RonLugge - validates_presence_of takes a :message argument, use that to specify your own message.
20

In Rails 3.2, validates_existence_of is replaced by validates_presence_of.

1 Comment

also possible is validates :category, :presence => true
4

I've put this in my model:

 validate :ensure_category_exists def ensure_category_exists errors.add('Category') unless self.blog.categories.find_by_id(self.category_id) end 

Which prints "Category is invalid" if the category does not exist for the parent blog.

Comments

2

It's definitely worth mentioning my experiences. This is for Rails 4 (potentially other versions as well).

Given an entity has_many or has_one of a model.

Validation that will ensure the entered association (association ID) exists, even if there is an ID given in the submission.

validates_presence_of :model 

IS NOT THE SAME as a validation that will ensure there is something entered (not blank) in the input.

validates_presence_of :model_id 

You may be able to get by with just the former, but I have both to have more specific error messages.

1 Comment

Issue with model_od is that when you just build models with relations, they don't have id before being saved and your validation of parent will blow. I was bitten by this.
0

In my way of thinking a better choice is this gem: https://github.com/perfectline/validates_existence

It validates the related model's existence in the database. Imagine you have a dropdown field that gives back some garbage data even when you do not select anything (default non selected first field label as value). Validating presence won't work, as it will pass for existing data. But we want some kind of a constraint and this DB side check is what solves the problem.

Comments

0

In rails 5 and above, belongs_to automatically validates for presence.

But if you use belongs_to :category, optional: true it does not validate presence, and you can then do post.update!(category: -1) which is not great. To fix that:

validates :category, presence: true, if: :category_id 

Just to be clear, the above is useful only when the association is optional.

Comments

-2

In Rails 3, validates_associated is probably what you're looking for? http://guides.rubyonrails.org/active_record_validations_callbacks.html#validates_associated

3 Comments

validates_associated will run the validations on the associated model, and fail the main model if the association is invalid. So it would validate existence, but has additional behavior the OP may or may not want.
I've tested this and validates_associated doesn't break if the associated model doesn't exist (as you would expect). I guess if only fails if the associated model does exist, has validations, and at least one of them fails.
As obvio171 said, validates_associated does NOT validate the existence of the association.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.