Why is my model firing the validation at the wrong time?
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.r开发者_JAVA百科b
:
/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?
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
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.
精彩评论