セットプチフォッカ

勉強したアウトプット、ときどきフォッカチオ作っていました

【Rails】collection_selectで表示するテキストには、Procを指定できる

事の発端

自分で作ったGem「jp_local_gov」を使って、自作サービスを実装しています。

f:id:ikmbear:20220303082449p:plain

実装にあたって、市区町村名のセレクトボックスが必要でした。

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.rubyonrails.org

困った時の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にわたり、それぞれの「都道府県名 市区町村名」として表示できるわけです。

f:id:ikmbear:20220303085115p:plain