ruby-on-railsrubycocoon-gem

Rails: array column inside nested attribute params wrong number of arguments (given 0, expected 1..2)


I don't know if it's relevant, but I'm using the Cocoon Gem.

My main resource that is saving is a Property.

I have nested attributed for this property called property_unit_attributes

params.require(:property).permit(
 ...
property_units_attributes: [:id, :rent, :floor, :suite_number, :square_feet, :unit_type[], :ceiling_height, :condition, :amenities, :_destroy]
);

The issue here is with unit_type which are checkboxes on the nested form that accepts these attributes

I will not include the entire form since all attributes save correctly except my array. Here are a few of my checkbox fields under :unit_type

<div class="field">
        <%= f.check_box :unit_type, { multiple: true, class: 'field__checkbox' }, 'condominium', nil %>
        <label>Condominium</label>
      </div>

      <div class="field">
        <%= f.check_box :unit_type, { multiple: true, class: 'field__checkbox' }, 'general_business', nil %>
        <label>General Business</label>
      </div>

      <div class="field">
        <%= f.check_box :unit_type, { multiple: true, class: 'field__checkbox' }, 'health_care', nil %>
        <label>Health Care</label>
      </div>

      <div class="field">
        <%= f.check_box :unit_type, { multiple: true, class: 'field__checkbox' }, 'hostpitality_or_hotel', nil %>
        <label>Hospitality / Hotel</label>
      </div>

And example of the rendered HTML:

<div class="field">
   <input class="field__checkbox" type="checkbox" value="land" name="property[property_units_attributes][0][unit_type][]" id="property_property_units_attributes_0_unit_type_land">
   <label>Land</label>
      </div>

When I submit the form, all attributes are shown in the request. I will just on the attributes:

"property_units_attributes"=>{"0"=>{"rent"=>"33.0", "floor"=>"33", "suite_number"=>"[FILTERED]", "square_feet"=>"33", "unit_type"=>["condominium", "industrial", "office"], "ceiling_height"=>"33.0", "condition"=>"3", "amenities"=>"3", "id"=>"10"}},

As you can see, I selected three checkboxes and they're placed in an array:

"unit_type"=>["condominium", "industrial", "office"]

On submit, I get this error: wrong number of arguments (given 0, expected 1..2)

This happens when I added [] on the :unit_type param under the nested attributes (see above).

If I remove it, the form submits, but that column isn't saved.

I want to reiterate that all other fields save correctly. It is only this array column that ignores it completely.

If you need more information or more code from other parts of the app, please let me in know in a comment.


Solution

  • To whitelist an array of scalar values you want to pass a hash key with an empty array:

    params.require(:property).permit(
     ...
      property_units_attributes: [
          :id, :rent, :floor, :suite_number, 
          :square_feet, :unit_type, :ceiling_height, 
          :condition, :amenities, :_destroy,
          unit_type: []
      ]
    )
    

    This syntax looks kind of like dark magic but its actually just plain old ruby:

    irb(main):001:0> [:foo, :bar, baz: 1]
    => [:foo, :bar, {:baz=>1}]
    

    Why does :unit_type[] cause "wrong number of arguments (given 0, expected 1..2)"?

    If you try :unit_type[0] you can see that it calls the bracket accessor method on the symbol :unit_type.

    irb(main):014:0> :unit_type[0]
    => "u"
    irb(main):015:0> :unit_type.method("[]")
    => #<Method: Symbol#[](*)>
    

    If you want to declare a symbol with brackets or any other character with special significance Ruby has a special syntax for that:

    :"unit_type[]" 
    

    Of course that won't fix the issue here as Rack already expands any params ending with brackets into arrays and hashes.