技術勉強ノート

日々の勉強をまとめます。Rails / JS / Go

【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.com

 

新たな課題、何故かドキュメントに記載が無い…

動作的には先述の通りの実装で課題は解決しました。

しかし先のQiitaでも触れられているようにドキュメントに記載が有りません。

本当に正式な実装として存在しているのか、内部でどんな処理を経ているのか、

気になって日課である昼寝ができなくなったので調べてみました。

 

ソースコードを追っていく

ドキュメントに記載されているGithubのリンクから

https://github.com/rails/rails/blob/477fae3eb3d3b3bfdbe28586fecb8578c0be4721/actionview/lib/action_view/helpers/form_helper.rb#L1708

 

check_boxメソッドの処理はたった1行
`@template.check_box(@object_name, method, objectify_options(options), checked_value, unchecked_value)`

 

↑のメソッドはFormBuilderクラスに定義されている。

@templateview_contextで、つまるところFormHelperの同名メソッドを呼ぶことになっているらしい。 

参考:https://blog.freedom-man.com/rails-formhelper-codereading/

 

# TODO: この辺りの正確な理解ができなかったので、後日view_contextについて調べる。

 

FormHelpercheck_boxでは、下記を実行

`Tags::CheckBox.new(object_name, method, self, checked_value, unchecked_value, options).render`

https://github.com/rails/rails/blob/477fae3eb3d3b3bfdbe28586fecb8578c0be4721/actionview/lib/action_view/helpers/form_helper.rb#L945

 

Tags::CheckBoxのrenderメソッドにてmultipleオプションで分岐が有る。

multipleがtrueなら add_default_name_and_id_for_value メソッドを呼ぶ。

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/actionview/lib/action_view/helpers/tags/check_box.rb#L23-L25

 

add_default_name_and_id_for_value メソッドはTags::Baseに存在。

そして add_default_name_and_id を呼ぶ。

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/actionview/lib/action_view/helpers/tags/base.rb#L83

 

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属性末尾に[]を付けるか否かを決定している!

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/actionview/lib/action_view/helpers/tags/base.rb#L108

 

結論

check_box に multiple オプションを渡すと、 inputのname属性末尾に[]が追加され、1つのkeyに複数のvalueを配列で送ることができる。

(なんでドキュメントに書かれていないのかは未だ謎のまま…) 

 

おまけ

Railsには、collection_check_boxes というヘルパーも有って、
単に multipleが常にtrueな check_box という実装でした。

https://github.com/rails/rails/blob/b2eb1d1c55a59fee1e6c4cba7030d8ceb524267c/actionview/lib/action_view/helpers/tags/collection_check_boxes.rb#L14