rails: Using accepts_nested_attributes for and :reject_if => :all_blank on deep nesting

Given the following models.

class Pet < ActiveRecord::Base
  has_and_belongs_to_many :owners
  accepts_nested_attributes_for :owners, :reject_if => :all_blank
end

class Owner < ActiveRecord::Base
  has_and_belongs_to_many :pets
  has_one :phone_number
  accepts_nested_attributes_for :phone_number
end

class PhoneNumber < ActiveRecord::Base
  belongs_to :owner
end

And a form like this.

= form_for @pet do |f|
  // pet fields here

  = f.fields_for :owners do |o|
    // owner fields here

    = o.fields_for :phone_number do |p|
      // phone number fields here

When the form is submitted with completely blank owner fields and phone number fields the :all_blank proc will return false because it checks only the top level owner parameters and it sees the phone_number_attributes parameter which has the type hash:ActionController::Parameters which is evaluated as not blank.

It would be helpful if the built in :all_blank proc looped through all child parameters as well as those of the top level. Of course custom procs can be written but in my opinion this is the expected behavior of :all_blank

About this issue

  • Original URL
  • State: closed
  • Created 9 years ago
  • Reactions: 1
  • Comments: 17 (9 by maintainers)

Most upvoted comments

I am running into this still with Rails 5.0.5. Just an FYI to anyone who lands on this issue from the year 2017 😃

I simplified my example. Having all_blank on the phone number does not matter since when the proc on owner is run to check for blanks it will always return false due to blank? thinking the phone_number_attributes parameter (which has the type hash:ActionController::Parameters) is not blank.

The quick hacky solution for my needs was to write this custom proc.

accepts_nested_attributes_for :owners, reject_if: proc { |attributes|
  attributes.all? do |key, value|
    if value.is_a? ActionController::Parameters
      value.all? { |nested_key, nested_value| nested_key == '_destroy' || nested_value.blank? }
    else
      key == '_destroy' || value.blank?
    end
  end
}

But it only goes one extra level deep (which is all I needed). Switching to a more robust proc that is recursive or can handle deep nesting would probably be wise. I spent far more time than I should have trying to figure out why my blank attributes weren’t being rejected.

It’s definitely still an issue in Rails 4.2.4 - what information do you need to keep this open?