heartcombo / simple_form

Forms made easy for Rails! It's tied to a simple DSL, with no opinion on markup.
http://blog.plataformatec.com.br/tag/simple_form
MIT License
8.21k stars 1.31k forks source link

Multiple inputs with the same name generate unparseable names in Rails >= 7.1.1 #1834

Closed nduitz closed 2 months ago

nduitz commented 6 months ago

Environment

Hey, there.

Rack changed how they parse query parameters which causes the usage of multiple inputs of the same name to generate unparseable query parameters.

Here is a quick example:

<%= simple_form_for :foo do |f| %>
  <%= f.input 'bar[][id]' %>
  <%= f.input 'bar[][id]' %>
  <%= f.input 'bar[][id]' %>
  <%= f.input 'bar[][id]' %>
<% end %>

The use case here is to create parameters that contain an array in bar which consists of hashes containing id keys.

Current behavior

This produces inputs with names like this: foo[bar[][id]] which is no longer supported by rack see https://github.com/rack/rack/issues/2128

The resulting parameters look like this:

"foo"=>{"bar["=>{"id"=>{"]"=>"33"}}}

Maybe this is not the intended way to create query params that contain an array containing hashes? I tried using simple_fields_for but I could not make it work

Expected behavior

I think the names generated by a form like this should follow the conventions mentioned by rails: https://guides.rubyonrails.org/form_helpers.html#understanding-parameter-naming-conventions

thus generating names like this:

foo[bar][][id]

Current Workaround

Simply setting the name manually by adding input_html: { name: '...' }

BTW:

If anyone could point out where this is implemented I am happy to create a PR but I currently don't have the time to dig this myself.

nashby commented 2 months ago

@nduitz hey! You indeed can use simple_fields_for to make it work properly:

<%= simple_form_for :bar, html: { class: "quote form" } do |f| %>
  <%= f.simple_fields_for 'foo', index: nil do |ff| %>
    <%= ff.text_field 'id' %>
    <%= ff.text_field 'id' %>
    <%= ff.text_field 'id' %>
    <%= ff.text_field 'id' %>
  <% end %>
  <%= f.submit :submit %>
<% end %>

<form class="simple_form quote form" action="/users/new" ...>
  <input type="text" name="bar[foo][][id]" id="bar_foo__id">
  <input type="text" name="bar[foo][][id]" id="bar_foo__id">
  <input type="text" name="bar[foo][][id]" id="bar_foo__id">
  <input type="text" name="bar[foo][][id]" id="bar_foo__id">
  <input type="submit" name="commit" value="submit" data-disable-with="submit">
</form>

And I believe that's what you have to use if you want to achieve something like that.