views:

112

answers:

2
class Gift < ActiveRecord::Base
  has_many :contributions
  accepts_nested_attributes_for :contributions, :reject_if => proc { |a| a['amount'].blank? }

Contribution has a :nickname attribute. In the :new form, it is pre-populated with the user's real name. A user might decide to change it to "Uncle Bob" (or whatever). Unfortunately, with :reject_if, if no amount is specified in the contribution, the :nickname change is lost when :new reloads in cases where @gift is not valid. This happens because the nested contribution_attributes are rejected. How do we preserve the :nickname change and only handle the rejection when @gift is actually saved?

A: 

I think you're looking for a validation in the Contribution model instead of a :reject_if clause.

:reject_if will throw away the entire record if the condition is met. Failed validations in the contribution model will block the associated gift from being saved. However @gift will retain the contribution regardless of its amount value on a failed save, allowing your user the chance to correct it, when the controller renders the new action again.

The solution is to remove the :reject_if clause from the accepts_nested_attributes_for statement, and add validates_presence_of_amount in the Contributions model.

class Gift < ActiveRecord::Base
  has_many :contributions
  accepts_nested_attributes_for :contributions
  ...
end

class Contribution < ActiveRecord::Base
  validates_presence_of :amount
  ...
end
EmFi
Yes, I have validates_presence_of :amount in Contribution. When the @gift form is submitted with: 1) blank Contribution fields, it works. (Gift discards the empty nest.) 2) with :amount, it works. (Validation is performed.) 3) with a :nickname but no :amount, it doesn't work. This is the default case, because we want the form pre-populated with user's full name in :nickname. Adding the :reject_if => a['amount'].blank?, removes any change the user makes to nickname. We want those changes to be preserved. Make sense?
Gavin
EmFi
A: 
class Gift < ActiveRecord::Base
  has_many :contributions
  accepts_nested_attributes_for :contributions,
    :reject_if => proc { |a| a['amount'].blank? }
end

class Contribution < ActiveRecord::Base
  belongs_to :gift
  validates_presence_of :nickname, :amount
end

...in the gift form...

f.text_field :nickname, :value => (params[:gift][:contributions_attributes]['0'][:nickname] rescue @m.full_name)

This preserves :nickname changes through failed validations and still discards a nested contributions that contain :nickname only.

Gavin