Reputation: 1519
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?
Upvotes: 18
Views: 24902
Reputation: 859
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.
Upvotes: 0
Reputation: 2962
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
Upvotes: 21
Reputation: 5847
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.
Upvotes: 2
Reputation: 660
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.
Upvotes: 0
Reputation: 2430
In Rails 3.2, validates_existence_of is replaced by validates_presence_of.
Upvotes: 20
Reputation: 183
In Rails 3, validates_associated
is probably what you're looking for?
http://guides.rubyonrails.org/active_record_validations_callbacks.html#validates_associated
Upvotes: -2
Reputation: 1519
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.
Upvotes: 4