为何radio_button_tag的两个关键字参数被解析为单个参数?
下面这段代码能正常禁用单选按钮:
<%= radio_button_tag 'set_creation_radio', 'set_editor', false, disabled: true %>
但改成带checked:关键字参数的写法后就失效了:
<%= radio_button_tag 'set_creation_radio', 'set_editor', checked: false, disabled: true %>
断点调试时发现两种写法的checked参数值完全不同:
第一种写法里,checked的值是布尔值:
0> checked => true
第二种写法里,checked被解析成了包含两个键的哈希:
0> checked => {:checked=>true, :disabled=>true}
以下是radio_button_tag的源码:
def radio_button_tag(name, value, checked = false, options = {}) 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 end
问题原因
核心是Ruby的参数传递规则:radio_button_tag的参数定义是位置参数,前三个分别是name、value、checked(默认值false),第四个是options(默认空哈希)。
- 第一种写法中,
false传给第三个位置参数checked,disabled: true作为哈希传给第四个options,完全符合参数定义,解析正常。 - 第二种写法中,直接传递的
checked: false, disabled: true属于关键字参数,但方法未声明关键字参数,Ruby会自动把这些关键字合并成一个哈希,传给第三个位置参数checked(前两个参数已传值),第四个options则使用默认空哈希。
这就导致:
checked变量变成非空哈希,Ruby中非空哈希会被判定为true,触发html_options["checked"] = "checked"逻辑,单选按钮被意外选中;disabled: true没有传入options,按钮不会被禁用,最终效果和预期完全相反。
正确写法
如果要同时设置选中状态和禁用属性,需严格按照方法参数顺序传递:
<%= radio_button_tag 'set_creation_radio', 'set_editor', false, disabled: true %>
这里第三个参数false控制选中状态(不选中),第四个哈希参数里的disabled: true控制禁用属性。
如果一定要用关键字参数的方式,需把HTML属性打包成哈希传给第四个参数:
<%= radio_button_tag 'set_creation_radio', 'set_editor', false, { checked: false, disabled: true } %>
注意:第三个位置参数的checked优先级更高,会覆盖options里的checked设置。
内容的提问来源于stack exchange,提问作者Jacob Miller
相关产品推荐
相关产品推荐

