Why is the first element always blank in my Rails multi-select, using an embedded array?

后端 未结 9 2267
我寻月下人不归
我寻月下人不归 2020-11-29 19:54

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

相关标签:
9条回答
  • 2020-11-29 20:10

    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.

    0 讨论(0)
  • 2020-11-29 20:10

    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.

    0 讨论(0)
  • 2020-11-29 20:13

    In the controller:

    arr = arr.delete_if { |x| x.empty? }
    
    0 讨论(0)
  • 2020-11-29 20:18

    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
    
    0 讨论(0)
  • 2020-11-29 20:19

    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.

    0 讨论(0)
  • 2020-11-29 20:21

    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 } %>
    
    0 讨论(0)
提交回复
热议问题