動かざることバグの如し

近づきたいよ 君の理想に

お前らのf.radio_buttonとf.labelは間違っている

環境

経緯

Rails生涯費用シミュレーターというのを作っていた。

で、form_withで作ったフォームの中にラジオボタンを作りたかったのだが、これがなかなかうまくできない

先にゴールの生成されるべきHTMLを示す。

<input type="radio" value="month" checked="checked" name="cost[pay_type]" id="cost_pay_type_month">
<label for="cost_pay_type_month">月額払い</label>

ラジオボタンは地味に厄介で、input[type=radio]要素のid属性とlabel要素のfor属性が一致してなければならない

そうしないと、文字をクリックして切り替えできないという面倒な仕様がある。ここでもラジオボタンの「id=cost_pay_type_month」とラベルタグの「for=cost_pay_type_month」が同じなのがわかる。

悲しいことにググっても中々答えにたどり着けなかったのでメモ

方法1(うまくいく例)

Railsなんて知らねえ!ってことで labelタグを直書きする。

<label>
<%= f.radio_button :pay_type, "month", checked: true %>月額払い
</label>

仕様とは異なるが、これでもラジオボタン自体を囲っているので文字をクリックしても反応する。悪くはないけど、i18n対応とか考えると明らかにレールに乗ってない記述である。あとダサい

方法2(うまくいかない例)

f.labelを使ってみる。がこれは失敗例 どうもググるvalueで文字列を渡すといいらしい。

<%= f.label :pay_type, :month, value: "月額払い" %>

で、生成されたLabelタグが以下

<label for="cost_pay_type_月額払い">month</label>

は???なんでfor属性に日本語が入ってるんだ???ってことで却下

方法3(うまくいかない例)

オーケーオーケー、どうやらvalueを指定するとfor属性のサフィックスに使われるらしい。ってことで monthを指定してみる。

<%= f.label :pay_type, :month, value: :month %>
<label for="cost_pay_type_month">month</label>

いけたやん!っと換気したのもつかの間、Labelタグ内の文字列を変更できないのである。けどタグ内の文字列を変更するにはvalue指定するしか、、とジレンマが発生する

方法4(うまくいく例)

キレた。forを直接書く

<%= f.label :pay_type, "月額払い", for: "cost_pay_type_month" %>

これでも以下のようなちゃんとラジオボタン用のラベルが生成される。

<label for="cost_pay_type_month">月額払い</label>

うーん、けどなんか違うんだよなぁ

方法5(最適解)

色々調べた結果、Railsのレールに一番乗った書き方は以下

<%= f.radio_button :pay_type, :month %>
<%= f.label :pay_type_month, "月額払い" %>

するとちゃんと以下のようなHTMLが生成される。

<input type="radio" value="month" name="cost[pay_type]" id="cost_pay_type_month">
<label for="cost_pay_type_month">月額払い</label>

おおー、あれ結局valueの指定はいらなかったの????

ずばり、

<%= f.radio_button ①, ② %>

① + ② の値を f.label の第1引数に渡せば良い。(_で連結させて

これ得るまで長かった、、、てかRailsのソース内のドキュメントにもlabelタグの書き方なかったし、なんなんだ、、

参考サイト