views: allow unselecting all values from a multiple dropdown

Currently, deselecting all values from a multiple dropdown rendered as
checkboxes doesn't have any effect when submitting the form (the
previous values are still there, instead of being deselected).

This is because unchecked checkboxes are not sent by the browser – so
the "empty selection" never gets sent.

Rails `form.check_box` usually works around this by inserting an empty
hidden checkbox element, that will be sent even if all others are
de-selected. But the documentation warns that this is not possible when
iterating over an array (rather than a model). Which is our case here.

To fix this, this commit uses `collection_check_boxes` instead. It will
insert the proper hidden checkboxes in all cases, and fix our use case.

See https://api.rubyonrails.org/classes/ActionView/Helpers/FormOptionsHelper.html#method-i-collection_check_boxes
This commit is contained in:
Pierre de La Morinerie 2020-08-25 10:47:36 +00:00
parent f15b96cb3a
commit 0800bf68d0
2 changed files with 9 additions and 4 deletions

View file

@ -1,10 +1,11 @@
- if champ.options?
- if champ.render_as_checkboxes?
- champ.enabled_non_empty_options.each do |option|
= form.collection_check_boxes(:value, champ.enabled_non_empty_options, :to_s, :to_s) do |b|
.editable-champ.editable-champ-checkbox
%label
= form.check_box :value, { multiple: true, checked: champ&.value&.include?(option) }, option, nil
= option
= b.label do
= b.check_box({ multiple: true, checked: champ&.value&.include?(b.value) })
= b.text
- else
= form.select :value,
champ.options,

View file

@ -72,6 +72,10 @@ describe 'shared/dossiers/edit.html.haml', type: :view do
it 'renders the list as checkboxes' do
expect(subject).to have_selector('input[type=checkbox]', count: enabled_options.count)
end
it 'adds an extra hidden input, to send a blank value even when all checkboxes are unchecked' do
expect(subject).to have_selector('input[type=hidden][value=""]')
end
end
context 'when the list is long' do