Homar
Homar

Reputation: 1519

Rails: Validating existence of an association

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

Answers (7)

Yoav Epstein
Yoav Epstein

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

Terry G Lorber
Terry G Lorber

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

karns
karns

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

Ikon
Ikon

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

thd
thd

Reputation: 2430

In Rails 3.2, validates_existence_of is replaced by validates_presence_of.

Upvotes: 20

cabgfx
cabgfx

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

Homar
Homar

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

Related Questions