Html 为什么我的 Rails 多选中的第一个元素总是空白,使用嵌入式数组?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8929230/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the first element always blank in my Rails multi-select, using an embedded array?
提问by robmclarty
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 select a subset of Array
and save their selection to the database, stored in a single column in Model
. I've used serialize on the database column which stores the Array
and Rails is correctly converting the users' selections into Yaml (and back to an array when reading that column). I'm using a multi-select form input to make selections.
我正在使用Rails 3.2.0.rc2。我有一个Model
,其中我有一个静态的Array
,我通过一个表单提供它,这样用户可以选择一个子集Array
并将他们的选择保存到数据库中,存储在Model
. 我在存储数据库列上使用了序列化Array
,Rails 正确地将用户的选择转换为 Yaml(并在读取该列时返回到数组)。我正在使用多选表单输入进行选择。
My problem is that, the way I currently have it, everything works as I would expect except that the user's subset array always has a blank first element when it's sent to the server.
我的问题是,按照我目前拥有的方式,除了用户的子集数组在发送到服务器时始终有一个空白的第一个元素之外,一切都按我的预期工作。
This isn't a big deal, and I could write code to cut that out after the fact, but I feel like I'm just making some kind of syntactical error as it doesn't seem to me that the default Rails behaviour would intentionally add this blank element without some reason. I must have missed something or forgot to disable some kind of setting. Please help me understand what I'm missing (or point me in to some good documentation that describes this with more depth than what I've been able to find on the intertubes).
这没什么大不了的,我可以编写代码在事后将其删除,但我觉得我只是犯了某种语法错误,因为在我看来,默认的 Rails 行为并不是故意的无故添加此空白元素。我一定是错过了什么或忘记禁用某种设置。请帮助我了解我缺少什么(或向我指出一些很好的文档,这些文档比我在插管上找到的内容更深入地描述了这一点)。
MySQL Database Table 'models':
MySQL 数据库表“模型”:
- includes a column named
subset_array
which is a TEXT field
- 包括一个名为
subset_array
TEXT 字段的列
Class Model includes the following settings:
类模型包括以下设置:
serialize :subset_array
ALL_POSSIBLE_VALUES = [value1, value2, value3, ...]
serialize :subset_array
ALL_POSSIBLE_VALUES = [value1, value2, value3, ...]
Form for editing Models includes the following input option:
用于编辑模型的表单包括以下输入选项:
f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array
f.select :subset_array, Model::ALL_POSSIBLE_VALUES, {}, :multiple => true, :selected => @model.subset_array
PUT to server from client looks something like this:
从客户端 PUT 到服务器看起来像这样:
- assuming only value1 and value3 are selected
"model" => { "subset_array" => ["", value1, value3] }
- 假设只选择了 value1 和 value3
"model" => { "subset_array" => ["", value1, value3] }
Database update looks like this:
数据库更新如下所示:
UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n'
UPDATE 'models' SET 'subset_array' = '--- \n- \"\"\n- value1\n- value3\n'
As you can see, there's this extra, blank, element in the array being sent and set in the database. How do I get rid of that? Is there a parameter I'm missing from my f.select
call?
如您所见,数组中有这个额外的空白元素被发送并设置在数据库中。我该如何摆脱它?我的f.select
通话中是否缺少参数?
Much thanks appreciated :)
非常感谢赞赏:)
EDIT: This is the generated HTML code from the f.select
statement. It looks as though there is a hidden input being generated which may be the cause of my issue? Why is that there?
编辑:这是从f.select
语句生成的 HTML 代码。看起来好像正在生成一个隐藏的输入,这可能是我的问题的原因?为什么会在那里?
<input name="model[subset_array][]" type="hidden" value>
<select id="model_subset_array" multiple="multiple" name="model[subset_array][]" selected="selected">
<option value="value1" selected="selected">Value1</option>
<option value="value2">Value2</option>
<option value="value3" selected="selected">Value3</option>
<option...>...</option>
</select>
采纳答案by Mike A.
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):
隐藏字段是导致问题的原因。但这有一个很好的理由:当所有值都被取消选择时,您仍然会收到一个 subset_array 参数。从 Rails 文档(您可能需要向右滚动才能看到所有这些):
# 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.
编辑:最后一段建议您在选择某些内容的情况下不应该看到空的,但我认为这是错误的。向 Rails 提交此承诺的人(参见https://github.com/rails/rails/commit/faba406fa15251cdc9588364d23c687a14ed6885)正在尝试使用 Rails 用于复选框的相同技巧(如此处所述:https: //github.com /rails/rails/pull/1552),但我认为它不适用于多选框,因为在这种情况下发送的参数形成一个数组,因此不会忽略任何值。
So my feeling is that this is a bug.
所以我的感觉是这是一个错误。
回答by Bogdan Gusiev
In Rails 4:
在 Rails 4 中:
You will be able to pass :include_hidden
option. https://github.com/rails/rails/pull/5414/files
您将能够通过:include_hidden
选项。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.
这只会删除模型级别的所有空白值。
回答by Martin
In Rails 4+ set :include_hidden on select_tag to false
在 Rails 4+ 中将 select_tag 上的 :include_hidden 设置为 false
<%= form.grouped_collection_select :employee_id, Company.all, :employees, :name, :id, :name, { include_hidden: false }, { size: 6, multiple: true } %>
回答by Max
Another quick fix is to use this controller filter:
另一个快速修复是使用这个控制器过滤器:
def clean_select_multiple_params hash = params
hash.each do |k, v|
case v
when Array then v.reject!(&:blank?)
when Hash then clean_select_multiple_params(v)
end
end
end
This way can be reused across controllers without touching the model layer.
这种方式可以在不接触模型层的情况下跨控制器重用。
回答by devishot
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html#method-i-check_box
Gotcha
The HTML specification says unchecked check boxes or selects are not successful, and thus web browsers do not send them. Unfortunately this introduces a gotcha: if an Invoice model has a paid flag, and in the form that edits a paid invoice the user unchecks its check box, no paid parameter is sent. So, any mass-assignment idiom like
@invoice.update(params[:invoice]) wouldn't update the flag.
To prevent this the helper generates an auxiliary hidden field before the very check box. The hidden field has the same name and its attributes mimic an unchecked check box.
This way, the client either sends only the hidden field (representing the check box is unchecked), 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.
陷阱
HTML 规范说未选中的复选框或选择不成功,因此 Web 浏览器不会发送它们。不幸的是,这引入了一个问题:如果发票模型具有已付标志,并且在编辑已付发票的表单中,用户取消选中其复选框,则不会发送已付参数。所以,任何大规模分配习语,如
@invoice.update(params[:invoice]) 不会更新标志。
为了防止这种情况,助手在复选框之前生成一个辅助隐藏字段。隐藏字段具有相同的名称,其属性模拟未选中的复选框。
这样,客户端要么只发送隐藏字段(表示复选框未选中),要么同时发送两个字段。由于 HTML 规范规定键/值对必须按照它们在表单中出现的相同顺序发送,并且参数提取获取查询字符串中任何重复键的最后一次出现,这适用于普通表单。
To remove blank values:
删除空白值:
def myfield=(value)
value.reject!(&:blank?)
write_attribute(:myfield, value)
end
回答by Mauro
In the controller:
在控制器中:
arr = arr.delete_if { |x| x.empty? }
回答by imaginabit
I make it work by writing this in the Javascript part of the page:
我通过在页面的 Javascript 部分编写它来使它工作:
$("#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.
不确定这是否会在将来让我头疼,但现在它工作正常。
回答by Bruno
I fixed it using the params[:review][:staff_ids].delete("")
in the controller before the update.
我params[:review][:staff_ids].delete("")
在更新之前使用控制器中的修复了它。
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
回答by user1875926
Use jQuery:
使用jQuery:
$('select option:empty').remove();
Option to remove blank options from drop down.
从下拉列表中删除空白选项的选项。