I\'m using Rails 3.2.0.rc2. I\'ve got a Model
, in which I have a static Array
which I\'m offering up through a form such that users may se
The hidden field is what is causing the issue. But it is there for a good reason: when all values are deselected, you still receive a subset_array parameter. From the Rails docs (you may have to scroll to the right to see all of this):
# The HTML specification says when +multiple+ parameter passed to select and all options got deselected
# web browsers do not send any value to server. Unfortunately this introduces a gotcha:
# if an +User+ model has many +roles+ and have +role_ids+ accessor, and in the form that edits roles of the user
# the user deselects all roles from +role_ids+ multiple select box, no +role_ids+ parameter is sent. So,
# any mass-assignment idiom like
#
# @user.update_attributes(params[:user])
#
# wouldn't update roles.
#
# To prevent this the helper generates an auxiliary hidden field before
# every multiple select. The hidden field has the same name as multiple select and blank value.
#
# This way, the client either sends only the hidden field (representing
# the deselected multiple select box), or both fields. Since the HTML specification
# says key/value pairs have to be sent in the same order they appear in the
# form, and parameters extraction gets the last occurrence of any repeated
# key in the query string, that works for ordinary forms.
EDIT: The last paragraph suggests that you shouldn't be seeing the empty one in the case when something is selected, but I think it is wrong. The person who made this commit to Rails (see https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885) is trying to do the same trick that Rails uses for checkboxes (as mentioned here: https://github.com/rails/rails/pull/1552), but I don't think it can work for a multiple select box because the parameters sent over form an array in this case and so no value is ignored.
So my feeling is that this is a bug.
In Rails 4:
You will be able to pass :include_hidden
option. https://github.com/rails/rails/pull/5414/files
As a quick fix for now: you can use right now in your model:
before_validation do |model|
model.subset_array.reject!(&:blank?) if model.subset_array
end
This will just delete all blank values at model level.
In the controller:
arr = arr.delete_if { |x| x.empty? }
I fixed it using the params[:review][:staff_ids].delete("")
in the controller before the update.
In my view:
= form_for @review do |f|
= f.collection_select :staff_ids, @business.staff, :id, :full_name, {}, {multiple:true}
= f.submit 'Submit Review'
In my controller:
class ReviewsController < ApplicationController
def create
....
params[:review][:staff_ids].delete("")
@review.update_attribute(:staff_ids, params[:review][:staff_ids].join(","))
....
end
end
I make it work by writing this in the Javascript part of the page:
$("#model_subset_array").val( <%= @model.subset_array %> );
Mine looks more like following:
$("#modela_modelb_ids").val( <%= @modela.modelb_ids %> );
Not sure if this is going to get me headache in the future but now it works fine.
In Rails 4+ set :include_hidden on select_tag to false
<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>