Hi, I am developing a rails 3.0.3 application and accepts_nested_attributes_for method is giving me pains. To simplify the issue, I created a new app and generated 2 models. users -------- name: string cars ------ user_id: integer name: string class User < ActiveRecord::Base has_many :cars accepts_nested_attributes_for :cars, :allow_destroy => true, :reject_if => proc { |attrs| attrs[''name''].blank? } end class Car < ActiveRecord::Base belongs_to :user end Very simple, huh? In console, I created a user and create 2 cars for the user. u = User.first u.cars_attributes={"0"=>{"id"=>2, "_destroy"=>"1"}} u.save This should destroy the car but didn''t. If I modify the User model like accepts_nested_attributes_for :cars, :allow_destroy => true Then, it works as I expect meaning it destroy the car with the same code in the console. If I modify the line like the following, it works also. accepts_nested_attributes_for :cars, :allow_destroy => true, :reject_if => proc { |attrs| attrs[''id''].blank? and attrs[''name''].blank? } As I understand it, reject_if option is only for new instance not for destroyed instance. Am I wrong? Sam -- Posted via http://www.ruby-forum.com/. -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.
Philip Hallstrom
2011-Jan-25 17:17 UTC
Re: Question about accepts_nested_attributes_for and reject_if
On Jan 24, 2011, at 9:44 PM, Sam Kong wrote:> Hi, > > I am developing a rails 3.0.3 application and > accepts_nested_attributes_for method is giving me pains. > > To simplify the issue, I created a new app and generated 2 models. > > users > -------- > name: string > > cars > ------ > user_id: integer > name: string > > class User < ActiveRecord::Base > has_many :cars > > accepts_nested_attributes_for :cars, :allow_destroy => true, > :reject_if => proc { |attrs| attrs[''name''].blank? } > end > > class Car < ActiveRecord::Base > belongs_to :user > end > > > Very simple, huh? > > In console, > > I created a user and create 2 cars for the user. > > u = User.first > u.cars_attributes={"0"=>{"id"=>2, "_destroy"=>"1"}} > u.save > > This should destroy the car but didn''t. > If I modify the User model like > > accepts_nested_attributes_for :cars, :allow_destroy => true > > Then, it works as I expect meaning it destroy the car with the same code > in the console. > > If I modify the line like the following, it works also. > > accepts_nested_attributes_for :cars, :allow_destroy => true, :reject_if > => proc { |attrs| attrs[''id''].blank? and attrs[''name''].blank? } > > As I understand it, reject_if option is only for new instance not for > destroyed instance. > Am I wrong?The docs seem to contradict each other. First... # You may also set a :reject_if proc to silently ignore any new record # hashes if they fail to pass your criteria. For example, the previous # example could be rewritten as: But then.... # Allows you to specify a Proc or a Symbol pointing to a method # that checks whether a record should be built for a certain attribute # hash. The hash is passed to the supplied Proc or the method # and it should return either +true+ or +false+. When no :reject_if # is specified, a record will be built for all attribute hashes that # do not have a <tt>_destroy</tt> value that evaluates to true. # Passing <tt>:all_blank</tt> instead of a Proc will create a proc # that will reject a record where all the attributes are blank. The code says the second is true... from active_record/nested_attributes.rb around line 376... It loops through all the nested attributes... - if the ''id'' is blank and we don''t reject the record, then build it. - else we have an ''id'' so find the record and if we don''t reject it, add it to the target and *then* mark it for destruction. Unless I''m reading it wrong :) attributes_collection.each do |attributes| attributes = attributes.with_indifferent_access if attributes[''id''].blank? unless reject_new_record?(association_name, attributes) association.build(attributes.except(*UNASSIGNABLE_KEYS)) end elsif existing_record = existing_records.detect { |record| record.id.to_s == attributes[''id''].to_s } association.send(:add_record_to_target_with_callbacks, existing_record) if !association.loaded? && !call_reject_if(association_name, attributes) assign_to_or_mark_for_destruction(existing_record, attributes, options[:allow_destroy]) else raise_nested_attributes_record_not_found(association_name, attributes[''id'']) end end -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org To unsubscribe from this group, send email to rubyonrails-talk+unsubscribe-/JYPxA39Uh5TLH3MbocFF+G/Ez6ZCGd0@public.gmane.org For more options, visit this group at http://groups.google.com/group/rubyonrails-talk?hl=en.