ヨージとプログラミング

プログラミング勉強の記録

【Rails】ransackで複数モデルから検索したい時

TL;DR

  • search_from_forヘルパーは使わない
  • viewでは検索ワードのみ取得
  • controllerで検索する

環境

Rails 5.2.4.1
Ruby 2.6.5
Ransack 2.3.2

ransackの通常の使い方の延長では無理だった

前提
channelモデルとpostモデルから、検索ワード一致のものをすべて検索したいとします。
1つのモデルから検索する方法はwebにもよく載っていると思います。

# よくあるransackの使い方
# controller
def index
  @search = Channel.ransack(params[:q])
  @results = @search.result
end
# view
# よくあるransackの使い方
= search_form_for @search do |f|
 .form-group
   = f.label :title_cont, "Title"
   = f.search_field :title_cont
 .actions
   = f.submit "Search"

ここらは説明不要ですね。
さて、それでは複数モデルから検索するにはどうしましょう?いろいろ検証してみました。

複数モデルからの検索でダメだった方法

検証からちょっと日がたったので若干うろ覚え…
[ダメ1] includesを使う方法

# controller
def index
  @search = Channel.includes(:post).ransack(params[:q])
end

[ダメ2] formにモデルを並列する方法

# controller
def index
  @channel = Channel.ransack(params[:q])
  @post = Post.ransack(params[:p])
end

# view
= search_form_for @channel, @posts do |f|
 .form-group
   = f.label :title_and_content_cont, "Title"
   = f.search_field :title_and_content_cont
 .actions
   = f.submit "Search"

解決方法

search_form_forヘルパーを使わない。通常のform_withでコントローラーに検索ワードを送る

# view
.search-container
  = form_with url: search_path, local: true, method: :get do |f|
    = f.text_field :q
    = f.submit "検索"

コントローラーで必要なモデル分の検索を行う

class ChannelsController < ApplicationController
  def search
    @q = params[:q]

    @channels = Channel.ransack(title_cont: @q).result
    @posts = Post.ransack(content_cont: @q).result
  end
  ・・・
end

あとはレンダリングすればOKです。
(参考)
Ransackで複数のモデルを一度に検索 - VoidCC