Find an article

Start typing to search the archive.

← All articles

Rule #2 for validating the presence of a belongs_to association

Do you have trouble validating the presence of a belongs_to association when nested parameters come from a form? I recently had the same problem, and in this post I share how to tackle it.

Recently, I’ve resolved one more problem concerning the presence validator and a belongs_to association. But it involves another thing: accepts_nested_attributes. Assume you have a nested form and the parent object doesn’t exist yet. You can have this issue, and here I will show you how to fix it.

Issue

Let’s say we have the following models and their relationships:

class Account
  has_one :user
  accepts_nested_attributes_for :user
end

class User
  belongs_to :account
  validates :account, :presence => true
end

Go to rails console and check the validator out:

irb(main):001:0> params = {:account => {:user_attributes => {}}}
irb(main):002:0> a = Account.new(params[:account])
irb(main):003:0> a.valid? # => false
irb(main):004:0> a.errors.full_messages # => ["User account can't be blank"]

So this is our challenge: we can’t save the account because the user can’t pass validation, as the account (the parent model) doesn’t exist yet! But removing the validator wouldn’t be the right solution. Do you agree with me?

Solution

The solution is very simple: just add one more option, :inverse_of, to has_one (or has_many, if that’s what you have). With this option, Rails won’t try to get the account from the database when the user is validated. The account will be retrieved from memory. If you aren’t familiar with this option, I strongly recommend reading the official Rails guide.

So change the account model and try it:

class Account
  has_one :user, :inverse_of => :account
  accepts_nested_attributes_for :user
end
irb(main):001:0> params = {:account => {:user_attributes => {}}}
irb(main):002:0> a = Account.new(params[:account])
irb(main):003:0> a.valid? # => true

I hope this article was helpful for you.