如何使check_box_tag在未选中时提交“false”或“0”参数?

41

使用以下check_box_tag:

<%= check_box_tag 'object[boolean_attribute]', 1, object.boolean_attribute %>

我只能单向更新布尔属性: 从false到true。
默认情况下未选中(因为object.boolean_attribute是false),我选中并提交表单,会发布一个:boolean_attribute => 1的参数。
但是,当我尝试从true更新为false时,没有参数被传递,因此boolean_attribute仍然为true。
换句话说,当默认选中(因为object.boolean_attribute为true)时,我取消选中并提交表单,不会发布:boolean_attribute => 0的参数。
如何使check_box_tag在取消选中时发布:boolean_attribute => 0参数?
从API中,我无法确定是否有一些选项可以轻松实现: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-check_box_tag 谢谢。
由于某些原因,我无法理解,在我的实际代码中(具有嵌套的多对多关联),hidden_field_tag 不起作用。
<%= hidden_field_tag 'order[preparations_attributes][][cooked]', nil %>
<%= check_box_tag 'order[preparations_attributes][][cooked]', '1', preparation.cooked? %>

现在我有相反的问题:我可以取消复选框并更新准备工作,但如果我勾选复选框,则会混淆参数。
以下是未选中框的发布参数:
Parameters: {"utf8"=>"✓", "authenticity_token"=>"bGgPGbk+Cuk2q+LEgqetmk4e7xie8dB3iMP9Cj3SUm0=", "order"=>{"customer_name"=>"Duccio Armenise", "duedate"=>"2012-04-25 09:24:00.000000", "preparations_attributes"=>[{"quantity"=>"1", "description"=>"custom recipe", "kind"=>"custom", "cooked"=>"", "recipe_id"=>"9", "id"=>"86", "quantities_attributes"=>[{"ingredient_id"=>"", "qty"=>"", "_destroy"=>"0"}, {"ingredient_id"=>"11", "qty"=>"5.0", "id"=>"193", "_destroy"=>"0"}], "_destroy"=>"0"}], "add_preparation"=>{"recipe_id"=>""}}, "continue"=>"Confirm", "id"=>"31"}

现在当我勾选复选框时,从"cooked"=>" "开始一片混乱,由于某些原因Rails过早地关闭了preparation_attributes哈希表!
Parameters: {"utf8"=>"✓", "authenticity_token"=>"bGgPGbk+Cuk2q+LEgqetmk4e7xie8dB3iMP9Cj3SUm0=", "order"=>{"customer_name"=>"Duccio Armenise", "duedate"=>"2012-04-25 09:24:00.000000", "preparations_attributes"=>[{"quantity"=>"1", "description"=>"custom recipe", "kind"=>"custom", "cooked"=>""}, {"cooked"=>"1", "recipe_id"=>"9", "id"=>"86", "quantities_attributes"=>[{"ingredient_id"=>"", "qty"=>"", "_destroy"=>"0"}, {"ingredient_id"=>"11", "qty"=>"5.0", "id"=>"193", "_destroy"=>"0"}], "_destroy"=>"0"}], "add_preparation"=>{"recipe_id"=>""}}, "continue"=>"Confirm", "id"=>"31"}

编辑 #2::

我认为我遇到了一个与深度嵌套资源表单和参数传递相关的Rails bug: https://github.com/rails/rails/issues/5937

目前,我通过使用select_tag使其正常工作:

<%= select_tag 'order[preparations_attributes][][cooked]', options_for_select({yes: 1, no: 0}, preparation.cooked? ? 1 : 0) %> 

我认为为了避免“隐藏字段陷阱”,使用select_tag进行切换是可接受的解决方法。

无论如何,感谢您提供的答案!

7个回答

52

check_box助手(不包括_tag)会添加隐藏字段来解决你的问题:

<%= check_box 'object', 'boolean_attribute', {}, 'true', 'false' %>

# result:
<input name="object[boolean_attribute]" type="hidden" value="false" />
<input id="object_boolean_attribute" name="object[boolean_attribute]" type="checkbox" value="true" />

更新: 处理嵌套资源(产品accepts_nested_attributes_for:行项目)

= form_for @product, url: '' do |f|
  %p
    = f.label :title
    = f.text_field :title

  = f.fields_for :line_items do |li|
    = li.check_box :approved
    = li.label :approved, li.object.id
    %br
  = f.submit

检查3个复选框中的2个会给我这样的params
{..., "product"=>{"title"=>"RoR book", "line_items_attributes"=>{"0"=>{"approved"=>"0", "id"=>"47"}, "1"=>{"approved"=>"1", "id"=>"48"}, "2"=>{"approved"=>"1", "id"=>"51"}}}, "commit"=>"Update Product", "action"=>"action1", "controller"=>"test"}
为了更具可读性,params以YAML格式显示:
product:
  title: RoR book
  line_items_attributes:
    '0':
      approved: '0'
      id: '47'
    '1':
      approved: '1'
      id: '48'
    '2':
      approved: '1'
      id: '51'

看到了吗?没有隐藏字段,但选中/未选中状态清晰可辨。

有了这个params,我可以使用一行代码来更新相关的line_items:

@product.update_attributes params[:product]

希望它有所帮助。


谢谢你的回复,但我需要一个 check_box_tag 的解决方案,因为在我的实际代码中,我正在更新一个嵌套资源。请在编辑中查看我的实际代码。你的解决方案也适用于嵌套资源表单吗? - Darme
是的,很合适!没有任何阻止你传递像'order[preparations_attributes][][cooked]'这样的东西而不是'object' - jdoe
目前我已经采用了一个解决方法,切换到了select_tag方案(请参见EDIT#2),但我也会测试您的建议... - Darme
1
你没有提到你的应用程序结构(MVC中的M)的任何信息,所以我无法提供更多帮助。让我们这样做:我将向您展示如何处理嵌套资源。这是一个经典的例子:Product has_many:line_items。LineItem有:approved字段。请查看我的UDP以了解如何通过check_box处理这些字段。 - jdoe
一个使用fields_for的重构尝试已经在我的待办列表中了,谢谢你的提示。所谓的bug与较低级别的方法有关,即使用hidden_field和check_box_tag结合起来。 - Darme
显示剩余3条评论

33

你可以在复选框上方使用一个隐藏字段:

<%= hidden_field_tag 'object[boolean_attribute]', nil %>

这种方式可以确保,即使你的复选框没有被选中,你仍会提交 nil。这对你有帮助么?


1
有更方便的方法。请看我的答案。 - jdoe
谢谢,我知道这种方法,但是因为某些原因,在我的实际应用程序中,这种方法不起作用(我有一些嵌套的多对多模型...)。我正在更新问题并附上我的实际代码... - Darme
1
我只是在玩这个,它工作得很好,我的控制器正在接收我想要的参数。然而,它破坏了我的测试,因为Capybara现在无法找到复选框,因为有两个具有相同ID的复选框。我将尝试以不同的方式来定位它,但似乎在同一页上出现两个相同的ID这样的做法有点hackish。 - counterbeing
您还可以验证是否确实希望Capybara定位到隐藏字段。如果不是,您可以在spec_helper.rb或等效文件中设置: Capybara.ignore_hidden_elements = false - Mauricio Moraes
这个答案的好处是它也适用于Formtastic gem,而目前该gem对于单个复选框的支持较差。 - bigtunacan

7

如果有人在使用布尔类型的列,并且使用了check_box_tag,请看这里。 这对我很有效。 <%= hidden_field_tag 'order[preparations_attributes][][cooked]', 'false' %> <%= check_box_tag 'order[preparations_attributes][][cooked]', true, preparation.cooked? %>


2

在我的Rails应用程序中,我需要在true和false周围添加单引号。

原始代码

<%= f.check_box :admin, {}, true, false %>

更新的代码

<%= f.check_box :admin, {}, 'true', 'false' %>

我希望这能帮助其他人!

0

对于类似复选框的数组,您也可以使用哈希表:

= hidden_field_tag "ad_ids[#{ad.token}]" , false
= check_box_tag "ad_ids[#{ad.token}]" , true, true

0
只需在控制器中添加!!params[:checkbox],就可以了。

0
你会不会只用 .present? 函数呢?nil 被视为不出现,因此结果为真或假。
= check_box_tag :show_nav, @obj.show_nav.present?

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接