簡単にできるかなと思って少しだけハマったのでform_with内でのcollection_selectの使い方を整理します。
#実現したい事
- ドロップボックスで選択した項目による検索
- ドロップボックスの中身はDBから取得
#環境
Ruby version 2.5.1
Rails version 5.1.6
#サンプル
Userが所属している会社の住所の都道府県で検索したい。
リレーションは下記の様になります。
User(tournament): belongs_to :company
Company(field): has_many :users
また、companyテーブルはprefectureというカラムを持っているとします。
= form_with(url: search_users_path, method: :get, local: true) do |form|
= form.label :"都道府県"
= form.collection_select :prefecture, Company.group(:prefecture).order(id: :desc), :prefecture, :prefecture, {prompt: ""}
= form.submit
各コードの説明します。
form_with: form_forとform_tagを合わせたものです。詳しくは他の記事を参照してください(【Rails 5】(新) form_with と (旧) form_tag, form_for の違い)。ここではsearch_users_pathにフォームの内容を送る様になっています。
local: trueはform_withはデフォルトで非同期通信で送信する様になっているので、これで無効にしています。(もちろん必要あれば有効にしてください。)
collection_selectはDBの情報を元にドロップボックスを生成するメソッドです。
下記にどの様に使われるかまとめます。コメント部分は上記の例で実際に記述した項目を書いています。
collection_select(
object, #今回はform_withで既にオブジェクトを渡しているので省略(省略しないとエラーになります。)
method, #:prefecture : paramsで送る時のkeyになります。つまり今回はparams[:prefecture]で選択したドロップボックスの項目が取得できます。
collection, #Company.group(:prefecture).order(id: :desc) : 実際にドロップボックスに入る配列を渡します。
value_method, #:prefecture : optionタグにセットされるvalue属性になります。<option value="ここに値が入る(今回はcompanyの都道府県の値)">
text_method, #:prefecture : optionタグにセットされる実際のテキストになります。つまり今回の場合は<option value="千葉県">千葉県</option>みたいなhtmlが出力されます。
options = {}, #{prompt: ""} : オプションです。このオプションではドロップボックスの一番上を空欄に指定しています。
html_options = {} #省略 : htmlオプションです。
)
collectionのところでCompany.group(:prefecture).order(id: :desc)としていますが、これはgroupメソッドを使ってCompanyモデルのprefectureカラムから重複を除いたものを出力しています。これをしないで例えばCompany.allとしてしまうと東京の会社が3社あったらドロップボックス内に"東京"が3つ出てきてしまいます。なのでgroupを使ってprefectureが同じものは1つだけ抽出しています。
あとはコントローラで選択した都道府県にある会社を抽出します。
#他のアクションは省略
def index
@users = User.all
end
def search
companies = Company.where(prefecture: params[:prefecture]) #選択した都道府県にある会社を全て取り出している。
@users = User.where(company_id: companies.pluck(:id)) #抽出した会社からidだけを取り出して、その会社に所属しているuserを抽出している。
render "index"
end
pluckの使い方は他の記事やサイト様にお任せしますが、companiesからidだけを抜き出して配列で出力してくれます。
#まとめ
見返すと大した事はしていないのですが、結構時間かかったのでまとめました。
もっと良い方法があれば教えていただけると助かります。
#参考情報
Can someone explain collection_select to me in clear, simple terms? (Stack Overflow)