rornoob.com >

Creating nested objects with validation of parent id


12-Oct-2009

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.

E.g.

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

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

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
  ...
end

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?

| |

del.icio.usDiggblogmarksNewsvineStumbleUponTechnoratiFurlReddit

Comments

[ 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 2-Sep-2012:
check out http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html. this will do the trick:

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

class Post < ActiveRecord::Base
belongs_to :member, :inverse_of => :posts
validates_presence_of :member
end
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
Name
Website
Heading
Comment