How can I make a check_box_tag to post a 'false' or '0' parameter when unchecked?
Solution 1
check_box
(w/o _tag
) helper adds hidden field to address your problem for you:
<%= 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" />
UPD: Dealing with nested resources (Product accepts_nested_attributes_for
:line_items)
= 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
Checking 2 of 3 checkboxes gives me the params
as this:
{..., "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
as YAML for readability:
product: title: RoR book line_items_attributes: '0': approved: '0' id: '47' '1': approved: '1' id: '48' '2': approved: '1' id: '51'
See? No hidden fields but checked/unchecked states are clearly distinguished.
Having this params
allows me to use one line of code to update associated line_items:
@product.update_attributes params[:product]
I hope it helps.
Solution 2
You could use a hidden field above the checkbox:
<%= hidden_field_tag 'object[boolean_attribute]', nil %>
This way, even if your checkbox isn't checked, you'll still get nil
submitted. Would that work for you?
Solution 3
If anyone have column type boolean and using check_box_tag
then look at this. It worked for me.
<%= hidden_field_tag 'order[preparations_attributes][][cooked]', 'false' %>
<%= check_box_tag 'order[preparations_attributes][][cooked]', true, preparation.cooked? %>
Solution 4
in my rails app I needed to add single quotes around the true and false.
Original code
<%= f.check_box :admin, {}, true, false %>
Updated Code
<%= f.check_box :admin, {}, 'true', 'false' %>
I hope that helps somebody else!
Darme
Helping the best teachers find their next students and vice-versa. Corsidia.com
Updated on July 09, 2022Comments
-
Darme almost 2 years
With the following check_box_tag:
<%= check_box_tag 'object[boolean_attribute]', 1, object.boolean_attribute %>
I can update the boolean_attribute in only one direction: from false to true.
When is unchecked by default (because object.boolean_attribute is false) and I check it and then submit the form, a :boolean_attribute => 1 parameter is posted.
But, when I try to update from true to false no param is passed, so the boolean_attribute remains true.
In other words, when is checked by default (because object.boolean_attribute is true) and I uncheck it and then submit the form, a :boolean_attribute => 0 is not posted.
How can I make this check_box_tag to post a :boolean_attribute => 0 parameter when unchecked?
From the api I can't figure out if there is some option to pass to easily achieve it: http://api.rubyonrails.org/classes/ActionView/Helpers/FormTagHelper.html#method-i-check_box_tag
Thank you.
EDIT
For some reason I cannot fathom, in my actual code (with a nested many-to-many association) the hidden_field_tag is not working.
<%= hidden_field_tag 'order[preparations_attributes][][cooked]', nil %> <%= check_box_tag 'order[preparations_attributes][][cooked]', '1', preparation.cooked? %>
Now I have the opposite problem: I can uncheck the checkbox and the preparation is updated as aspected, but if I check the checkbox it messes up the params.
Here are the posted params for the unchecked box:
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"}
Now see what a mess when I check the checkbox, beginning from "cooked"=>" ", for some reason Rails is closing the preparation_attributes hash too early!
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"}
EDIT #2:
I think I ran into a Rails bug related to deep nested resource forms and param passing: https://github.com/rails/rails/issues/5937
For now I made it to work with a select_tag:
<%= select_tag 'order[preparations_attributes][][cooked]', options_for_select({yes: 1, no: 0}, preparation.cooked? ? 1 : 0) %>
I think that switching to a select_tag in order to avoid the "hidden_field gotcha" is an acceptable workaround.
Anyway, thank you for the answers!
-
jdoe about 12 yearsThere is more convenient approach. See my answer.
-
Darme about 12 yearsThank you, I knew this approach, I'm after something else because for some reason in my real app this is not working (I have some nested many-to-many models...). I'm updating the question with my actual code...
-
Darme about 12 yearsThank you but I was after a check_box_tag solution because in my actual code I am updating a nested resource. See my actual code in the edit. Is you solution applicable to a nested resource form as well?
-
jdoe about 12 yearsYes, it is suitable! Nothing prevents you from passing something like
'order[preparations_attributes][][cooked]'
instead of'object'
. -
Darme about 12 yearsFor now I made a workaround switching to a select_tag solution (see EDIT#2), but I'm going to test your suggestion as well...
-
Darme about 12 years...uhm, I tried as you suggested and with nil instead of 'boolean_attribute' but there are some unwelcome '[]' at the end of the name: <input type="checkbox" value="true" name="order[preparations_attributes][][cooked][]" id="order_preparations_attributes__cooked_"> name should be ="order[preparations_attributes][][cooked]" in order for this to work, any other idea?
-
jdoe about 12 yearsYou didn't say a word about the structure of your app (aboute the M in MVC) so I couldn't be more helpful. Let's make it this way: I'll show you the way of dealing with nested resources. It's a classic example: Product has_many :line_items. LineItem has
:approved
field. Check my UDP to dealing with this fields viacheck_box
. -
Darme about 12 yearsYou're right. Since in my actual app I have 3 level nesting (with many-to-many) I tried to boil my problem down to its essential. I knew this approach but in my case I really needed a lower-level one with check_box_tag or select_tag. If you are interested in the bug I think I ran into, here is the link: github.com/rails/rails/issues/5937
-
jdoe about 12 yearsRails perfectly handles nested
fields_for
. Using= f.fields_for :line_items do |li_form|
gives youli_form
which can be used in its turn to build another nesting:= li_form.fields_for :order do |order_form|
. Just checked:@product.update_attributes params[:product]
works, zeros for unchecked checkboxes appear in params. -
Darme about 12 yearsA refactor attempt using fields_for was already in my todo list, thank you for the hint. The alleged bug is related to a lower-level approach, namely, the use of hidden_field in conjunction to check_box_tag.
-
counterbeing almost 11 yearsI was just playing with this, and it works nicely, my controller is receiving the params I want. However, it broke my tests because Capybara now can't find the checkbox since there are two checkboxes with the same ID. I'm going to try to target it a different way, but it seems that doing something like this where you end up with two of the same ids on the same page is a bit hackish.
-
Mauricio Moraes over 10 yearsYou can also verify if you really want to have capybara target your hidden fields. If not, you can set in your spec_helper.rb or equivalent: Capybara.ignore_hidden_elements = false
-
bigtunacan about 10 yearsNice thing about this answer is that it also works with the Formtastic gem, which at the current time has poor support for an individual checkbox.