Support `checked` as a keyword argument in `check_box_tag` and `radio_button_tag`

Currently if you do this:

```ruby
check_box_tag "admin", "1", checked: false
```

It is treated [as truthy](19f9922523/actionview/lib/action_view/helpers/form_tag_helper.rb (L444)), and your checkbox is checked. This can be a bit surprising, particularly because the `FormHelper` version [does support](19f9922523/actionview/lib/action_view/helpers/form_helper.rb (L1285)) a keyword argument.

```ruby
f.check_box "admin", checked: false
```

So this PR updates `check_box_tag` and `radio_button_tag` to support `checked` as a positional or keyword argument, this way you can use the same API in both cases.

Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>
This commit is contained in:
Alex Ghiculescu 2022-07-05 17:16:22 -05:00
parent 0c4d89c2b5
commit 4fcac154f4
3 changed files with 94 additions and 2 deletions

View File

@ -1,3 +1,17 @@
* `check_box_tag` and `radio_button_tag` now accept `checked` as a keyword argument
This is to make the API more consistent with the `FormHelper` variants. You can now provide `checked` as a positional or keyword argument:
```erb
= check_box_tag "admin", "1", false
= check_box_tag "admin", "1", checked: false
= radio_button_tag 'favorite_color', 'maroon', false
= radio_button_tag 'favorite_color', 'maroon', checked: false
```
*Alex Ghiculescu*
* Allow passing a class to `dom_id`.
You no longer need to call `new` when passing a class to `dom_id`.
This makes `dom_id` behave like `dom_class` in this regard.

View File

@ -422,9 +422,17 @@ module ActionView
content_tag :textarea, content.to_s.html_safe, { "name" => name, "id" => sanitize_to_id(name) }.update(options)
end
##
# :call-seq:
# check_box_tag(name, options = {})
# check_box_tag(name, value, options = {})
# check_box_tag(name, value, checked, options = {})
#
# Creates a check box form input tag.
#
# ==== Options
# * <tt>:value</tt> - The value of the input. Defaults to <tt>"1"</tt>.
# * <tt>:checked</tt> - If set to true, the checkbox will be checked by default.
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
# * Any other key creates standard HTML options for the tag.
#
@ -443,16 +451,27 @@ module ActionView
#
# check_box_tag 'eula', 'accepted', false, disabled: true
# # => <input disabled="disabled" id="eula" name="eula" type="checkbox" value="accepted" />
def check_box_tag(name, value = "1", checked = false, options = {})
def check_box_tag(name, *args)
if args.length >= 4
raise ArgumentError, "wrong number of arguments (given #{args.length + 1}, expected 1..4)"
end
options = args.extract_options!
value, checked = args.empty? ? ["1", false] : [*args, false]
html_options = { "type" => "checkbox", "name" => name, "id" => sanitize_to_id(name), "value" => value }.update(options.stringify_keys)
html_options["checked"] = "checked" if checked
tag :input, html_options
end
##
# :call-seq:
# radio_button_tag(name, value, options = {})
# radio_button_tag(name, value, checked, options = {})
#
# Creates a radio button; use groups of radio buttons named the same to allow users to
# select from a group of options.
#
# ==== Options
# * <tt>:checked</tt> - If set to true, the radio button will be selected by default.
# * <tt>:disabled</tt> - If set to true, the user will not be able to use this input.
# * Any other key creates standard HTML options for the tag.
#
@ -468,7 +487,12 @@ module ActionView
#
# radio_button_tag 'color', "green", true, class: "color_input"
# # => <input checked="checked" class="color_input" id="color_green" name="color" type="radio" value="green" />
def radio_button_tag(name, value, checked = false, options = {})
def radio_button_tag(name, value, *args)
if args.length >= 3
raise ArgumentError, "wrong number of arguments (given #{args.length + 2}, expected 2..4)"
end
options = args.extract_options!
checked = args.empty? ? false : args.first
html_options = { "type" => "radio", "name" => name, "id" => "#{sanitize_to_id(name)}_#{sanitize_to_id(value)}", "value" => value }.update(options.stringify_keys)
html_options["checked"] = "checked" if checked
tag :input, html_options

View File

@ -88,6 +88,36 @@ class FormTagHelperTest < ActionView::TestCase
assert_dom_equal expected, actual
end
def test_check_box_tag_checked_kwarg_true
actual = check_box_tag "admin", "yes", checked: true
expected = %(<input id="admin" checked="checked" name="admin" type="checkbox" value="yes" />)
assert_dom_equal expected, actual
end
def test_check_box_tag_checked_kwarg_false
actual = check_box_tag "admin", "1", checked: false
expected = %(<input id="admin" name="admin" type="checkbox" value="1" />)
assert_dom_equal expected, actual
end
def test_check_box_tag_checked_kwarg_false_and_disabled
actual = check_box_tag "admin", "1", checked: false, disabled: true
expected = %(<input id="admin" name="admin" type="checkbox" value="1" disabled="disabled" />)
assert_dom_equal expected, actual
end
def test_check_box_tag_checked_kwarg_true_value_argument_skipped
actual = check_box_tag "admin", checked: true
expected = %(<input id="admin" checked="checked" name="admin" type="checkbox" value="1" />)
assert_dom_equal expected, actual
end
def test_check_box_tag_value_kwarg
actual = check_box_tag "admin", value: "0", checked: true
expected = %(<input id="admin" name="admin" type="checkbox" value="0" checked="checked" />)
assert_dom_equal expected, actual
end
def test_check_box_tag_id_sanitized
label_elem = root_elem(check_box_tag("project[2][admin]"))
assert_match VALID_HTML_ID, label_elem["id"]
@ -374,6 +404,30 @@ class FormTagHelperTest < ActionView::TestCase
actual = radio_button_tag("ctrlname", "apache2.2")
expected = %(<input id="ctrlname_apache2.2" name="ctrlname" type="radio" value="apache2.2" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", true
expected = %(<input id="people_david" name="people" type="radio" value="david" checked="checked" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", false
expected = %(<input id="people_david" name="people" type="radio" value="david" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", false, disabled: true
expected = %(<input id="people_david" name="people" type="radio" value="david" disabled="disabled" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", checked: true
expected = %(<input id="people_david" name="people" type="radio" value="david" checked="checked" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", checked: false
expected = %(<input id="people_david" name="people" type="radio" value="david" />)
assert_dom_equal expected, actual
actual = radio_button_tag "people", "david", checked: false, disabled: true
expected = %(<input id="people_david" name="people" type="radio" value="david" disabled="disabled" />)
assert_dom_equal expected, actual
end
def test_select_tag