views:

38

answers:

2

In my edit action of my employees_controller I have this line of code:

#Employee#edit
69: if @employee.user.person.addresses.length == 0
70:   @employee.user.person.addresses << Address.new
71: end

which should add a blank Address if there are none so it will show up in my edit erb file. That way if there were no Addresses associated with this employee, they are forced to add one when they edit this record.

There is a polymorphic association like this: Person <- User <- Employee and Person has a many-to-many relationship with Address. That declaration looks like this:

#class Person
has_many :address_person_links, :dependent => :destroy
has_many :addresses,
  :through => :address_person_links,
  :uniq => true,
  :validate => false, # I thought this would fix it but doesn't
  :dependent => :destroy

The code fails on line 70 of employees_controller.rb:

/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/validations.rb:1090:in `save_without_dirty!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/dirty.rb:87:in `save_without_transactions!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:182:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:208:in `rollback_active_record_state!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:200:in `save!'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/has_many_through_association.rb:63:in `insert_record'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:119:in `<<'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:433:in `add_record_to_target_with_callbacks'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:118:in `<<'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:116:in `each'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:116:in `<<'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:141:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/connection_adapters/abstract/database_statements.rb:136:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/transactions.rb:182:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:140:in `transaction'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.3.5/lib/active_record/associations/association_collection.rb:115:in `<<'
/home/aaron/NetBeansProjects/onlinescheduler/app/controllers/employees_controller.rb:70:in `edit'

Notice how its calling save? Why is it doing this?

+1  A: 

This is happening because whenever you add an AR object to an association array it will save the object and try and add its id to the association table (if it is many_to_many)

You may try the following

#Employee#edit
69: if @employee.user.person.addresses.length == 0
70:   @employee.user.person.addresses = [Address.new]
71: end

Also if you are doing this with accepts_nested_attributes_for the convention is to use the build method

#Employee#edit
69: if @employee.user.person.addresses.length == 0
70:   @employee.user.person.addresses.build
71: end

See http://ryandaigle.com/articles/2009/2/1/what-s-new-in-edge-rails-nested-attributes for more information

Will
+1  A: 

First, may I suggest you check as follows, for semantic clarity:

if @employee.user.person.addresses.empty?

Next, if you check your logs you will see that addresses (and the corresponding address_person_link) are added to the database by the "<<" method, this in turn calls the validation and this is why your save fails (as a newly created address doesn't validate).

You could modify your address validations to avoid running them if it's a newly created record (such as when you just added it to a person using "<<". Like this:

validates_presence_of :name, :unless => Proc.new{|a|a.new_record?}

You'd have to add the :unless block to every one on your validations on Address.

Roadmaster