【Rails】collection_selectで表示するテキストには、Procを指定できる
事の発端
自分で作ったGem「jp_local_gov」を使って、自作サービスを実装しています。
実装にあたって、市区町村名のセレクトボックスが必要でした。
jp_local_gov
ではView Templateに記載の通り、collection_select
で使用する候補を返すことを目的の一つとしたJpLocalGov.all
というAPIを実装しているので、一見以下の形式で目的は達成できそうです。
f.collection_select :local_gov_code, JpLocalGov.all, :code, :city
たしかにこれでも動作としては問題ないのですが、city
としか指定していないので、「市区町村名」しか表示されません。
日本には「都道府県は異なるけど、市区町村名が同じ市区町村」がそこそこ存在します。
JpLocalGov.all.group_by(&:city).select { |k, v| v.size > 1 }.map { |k, v| { k => v.map(&:prefecture) }} => [{"伊達市"=>["北海道", "福島県"]}, {"松前町"=>["北海道", "愛媛県"]}, {"森町"=>["北海道", "静岡県"]}, ...
そのため、都道府県と市区町村を合わせてテキストに表示したかったので、雑に以下のようにやってみたのですが動かず。
f.collection_select :local_gov_code, JpLocalGov.all, :code, "#{prefecture}#{:city}"
collection_selectで表示するvalueとtextにはProcを指定できる
困った時のAPI Dockというわけでチェックしてみると、
The :value_method and :text_method parameters are methods to be called on each member of collection. The return values are used as the value attribute and contents of each
要はcollection_selectの第1引数に指定したオブジェクトが対応できるメソッドを呼び出すことができ、それゆえにProcも呼び出せるようです。
結果として、
f.collection_select :local_gov_code, JpLocalGov.all, :code, ->(lg) { "#{lg.prefecture} #{lg.city}" }
こんな感じにProcを渡してあげると、JpLocaGov.all
で取得されたすべての市区町村がイテレーションされてlg
にわたり、それぞれの「都道府県名 市区町村名」として表示できるわけです。