【Rails】check_boxのmultipleオプションが気になったので調べてみた
はじめに
普段業務でRailsを使っています。
今日は、Railsの便利なフォームヘルパーの1つcheck_boxにmultipleオプションが存在することを知りました。
しかし、Railsのドキュメントには載っていないという…
check_box - リファレンス - - Railsドキュメント
なんだか気味が悪いのでソースコードリーディングしてみました。
直面した課題
ある案件で、チェックボックスで、同じkeyで複数の値を送りたくなりました。
例えば、「エリア選択で、東京と愛知と大阪を選びたい」というようなシチュエーション。
何も考えずにcheck_boxを作ると、チェックをつけた中で、一番後に記述されているフィールドのvalueだけが送信されてしまいます。
解決策
この時、check_box (or check_box_tag)のmultipleオプションにtrueを渡すと、
URLのパラメータが area_ids[]=13&area_ids[]=23
のような形になり、
params[:area_ids] #=[13,23]
のように複数の値をarrayで受け取ることができます。
参考:
新たな課題、何故かドキュメントに記載が無い…
動作的には先述の通りの実装で課題は解決しました。
しかし先のQiitaでも触れられているようにドキュメントに記載が有りません。
本当に正式な実装として存在しているのか、内部でどんな処理を経ているのか、
気になって日課である昼寝ができなくなったので調べてみました。
ソースコードを追っていく
ドキュメントに記載されているGithubのリンクから
check_boxメソッドの処理はたった1行
`@template.check_box(@object_name, method, objectify_options(options), checked_value, unchecked_value)`
↑のメソッドはFormBuilderクラスに定義されている。
@templateはview_contextで、つまるところFormHelperの同名メソッドを呼ぶことになっているらしい。
参考:https://blog.freedom-man.com/rails-formhelper-codereading/
# TODO: この辺りの正確な理解ができなかったので、後日view_contextについて調べる。
FormHelperのcheck_boxでは、下記を実行
`Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render`
Tags::CheckBoxのrenderメソッドにてmultipleオプションで分岐が有る。
multipleがtrueなら add_default_name_and_id_for_value メソッドを呼ぶ。
add_default_name_and_id_for_value メソッドはTags::Baseに存在。
そして add_default_name_and_id を呼ぶ。
add_default_name_and_id の中で、inputタグのname属性を指定している箇所が有り、nameオプションが渡されていなければ、tag_name メソッドを読んでいる。(Hash#fetchの仕様)
そしてその tag_name メソッドにmultipleオプションを渡している。
`options["name"] = options.fetch("name") { tag_name(options["multiple"], index) }`
https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/actionview/lib/action_view/helpers/tags/base.rb#L96
そして、、、
tag_name メソッドではmultipleオプションを使って分岐をし、inputのname属性末尾に[]
を付けるか否かを決定している!
結論
check_box に multiple オプションを渡すと、 inputのname属性末尾に[]
が追加され、1つのkeyに複数のvalueを配列で送ることができる。
(なんでドキュメントに書かれていないのかは未だ謎のまま…)
おまけ
Railsには、collection_check_boxes というヘルパーも有って、
単に multipleが常にtrueな check_box という実装でした。