Creating nested objects with validation of parent id


Nested attributes in rails 2.3.3 can really simplify the updating of nested models, but creating nested models throws up an interesting problem when your model uses validates_presence_of... at least it does for me...

Lets say I have two models, a User and an Account. The User accepts nested attributes for the Account, while the Account requires the presence of a user_id.


class User < ActiveRecord::Base
  has_many :accounts
  accepts_nested_attributes_for :accounts

class Account < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :user_id

Now when I go to create a new user and account, up pops a validation error:

ActiveRecord::RecordInvalid: Validation failed: Accounts user can't be blank

It doesn't take much to work out that the error is due to the account object being saved before the user object - i.e. the user doesn't yet exist in the database and so doesn't have a user_id. This causes the validates_presence_of :user_id clause in the account model to fail.

I thought about simply removing the check for user_id but my user and account objects are part of a legacy system - i.e. they're used in other places and I don't want to risk removing validations that are probably required.

So what to do?

The solution I'm going with is to conditionally validate the presence of the user_id - i.e. require the validation only if the account object is being created as part of a dependent creation of a user object.

I've modified my code to set an attribute :new_user on the account when creating a new user with nested account, then check for this attribute as follows:

class Account < ActiveRecord::Base
  belongs_to :user
  validates_presence_of :user_id, :unless => :new_user
  attr_accessor :new_user

That seems to do the trick - the validation message disappears and I'm able to create new users with embedded accounts.

Hopefully this issue will be fixed in a future version of rails. Until then... does anyone have a better solution I could use?

| |



[ Click to add a comment ]
Robert said on 3-Feb-2010:
Thanks, it worked for me!
dipnlik said on 8-May-2012:
Great idea, thanks or sharing :D
Michael said on 3-Sep-2012:
check out this will do the trick:

class Member < ActiveRecord::Base
has_many :posts, :inverse_of => :member
accepts_nested_attributes_for :posts

class Post < ActiveRecord::Base
belongs_to :member, :inverse_of => :posts
validates_presence_of :member
RoRnoob said on 3-Sep-2012:
Thanks Michael. I was using rails 2.3.3 at the time and it doesn't look like :inverse_of was supported back then.
Go to first comment
Add your comment