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 [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/rubyonrails-talk?hl=en.

Reply via email to