Be Genius

me

Bo Jeanes

I am an software engineer who has lived and worked in New York, Brisbane, Chicago, San Francisco, and now Melbourne. I primarily work in Ruby though am a functional programmer at heart and a fan of programming languages in general. In particular, I love Rust and Clojure but keep my eye on many langauges all the time.

Using accepts_nested_attributes_for When the Child Object validates_presence_of Parent

I came across an interesting dilemma today in Rails 2.3 whilst trying to use accepts_nested_attributes_for.

The models I have were:

class Organization < ActiveRecord::Base
  has_many :users
  accepts_nested_attributes_for :users
end

class User < ActiveRecord::Base
  belongs_to :organization
  validates_presence_of :organization
end

I had an “Organization” creation form which allowed an administrator to create an Organization and an initial user for it. However, even though I had filled in all the required fields to pass the validations I was constantly getting the following error: Organization can not be blank.

Digging deeper I found that when an object is added to an association via the association.build method, the parent object isn’t actually set:

>> o = Organization.new(:name => "Test")
=> #<Organization id: nil, name: "Test">
>> u = o.users.build(:name => "Test User")  
=> #<User id: nil, organization_id: nil, name: "Test User">
>> u.organization
=> nil

Apparently this flaw also applies to accepts_nested_attributes_for. When I send through the User params through from my form normally with the Organization params, it creates the User object in the users association as you’d expect, but raises a validation error because the User instance doesn’t recognise that it is has a parent Organization

My quick 5 minute fix was to modify the Organization model thusly:

class Organization < ActiveRecord::Base
  has_many :users
  accepts_nested_attributes_for :users

  def users_attributes_with_self_assignment=(attributes)
    self.users_attributes_without_self_assignment = attributes
    users.each { |u| u.organization = self }
  end
  alias_method_chain :users_attributes=, :self_assignment
end

Related Rails bugs seem to be here and here. This patch will also solve the problem and is currently in edge, but didn’t make it in time for Rails 2.3.

Comments

None yet

You need to login with GitHub in order to comment.