【Rails】Gem、ransackで複数カラム+条件から検索する


検索条件の概要

フリマアプリでGem ransack を用い、複数カラムから検索する方法で実装しました。

商品のタイトルか、本文のどちらかにキーワードがあるかつ指定した条件に当てはまっていれば商品がヒットします。
検索バーのビューは以下です。

ちなみにテーブルは以下のようになっています。

カテゴリー   … genre
商品の状態   … status
送料負担    … bear
発送までの日数  … day
価格      … price

です。「カテゴリー」、「商品の状態」、「送料負担」、「発送までの日数」はActiveHashを用いて、テーブルにはidだけ保存しています。
上記の項目+キーワード(商品のタイトルか、テキストの中身)全てにヒットしたものを絞れるという検索を実行したいと思います。

Controllerの記述

item_controller
class ItemsController < ApplicationController
  # index,show,searchページに検索窓のヘッダーを設置しているため、そのアクションの時に実行
  before_action :search_product, only: [:index, :show, :search]

  #省略

  private

 def search_product
    @p = Item.ransack(params[:q])  # 検索オブジェクトを生成
    @results = @p.result
  end
end

(params[:q])の:qは、検索パラメータのデフォルトのパラメータキーです。
以下は同義ですが、すでに他の場所でsearchが定義されている場合はデフォルトのransackメソッドを使用することができます。
Item.ransack(params[:q])
Item.search(params[:q])

@p = Item.ransack(params[:q])ここで検索オブジェクトを生成した後に、
@results = @p.resultで検索結果を@resultsに入れています。

検索バーの記述

検索のビュー
# @pに検索の情報を入れて、コントローラーに渡します。
<%= search_form_for @p, url: search_items_path do |f| %>
  <div class = 'nav-up'>
# :title_or_text_contは、text_fieldに入力した文字がtitleかtextの中に含まれているか、という記述
    <%= f.text_field :title_or_text_cont, placeholder: "キーワードから探す", class: "input-box" %>
    <button class="search-button">
      <%= image_tag("search.png", class:"search-icon")  %>
    </button>
  </div>
  <div class='nav-down'>
    <div class='label-select'>
      <%= f.label :genre_id_eq, 'カテゴリー', class: 'label' %>
      <%= f.collection_select :genre_id_eq, Genre.where.not(id: 0), :id, :name,  include_blank: '指定なし', class: 'search-select' %>
    </div>
    <div class='label-select'>
      <%= f.label :status_id_eq, '商品の状態', class: 'label' %>
      <%= f.collection_select :status_id_eq, Status.where.not(id: 0), :id, :name,  include_blank: '指定なし', class: 'search-select' %>
    </div>
    <div class='label-select'>
      <%= f.label :bear_id_eq, '送料負担', class: 'label' %>
      <%= f.collection_select :bear_id_eq, Bear.where.not(id: 0), :id, :name,  include_blank: '指定なし', class: 'search-select' %>
    </div>
    <div class='label-select'>
      <%= f.label :day_id_eq, '発送までの日数', class: 'label' %>
      <%= f.collection_select :day_id_eq, Day.where.not(id: 0), :id, :name,  include_blank: '指定なし', class: 'search-select' %>
    </div>
    <div class='label-select'>
      <%= f.label :price, '価格', class: 'label' %>
      <%= f.radio_button :price_lteq, '' %>
      指定なし
      <%= f.radio_button :price_lteq, '1000' %>
      1000円以下
      <%= f.radio_button :price_lteq, '2500' %>
      2500円以下
      <%= f.radio_button :price_lteq, '5000' %>
      5000円以下
      <br>
    </div>
  </div>
<% end %>

検索結果を表示させるビュー

search.html.erb
<% if @results.present? %>
  <ul class='item-lists'>
    <% @results.each do |item| %>
      <%= render partial: "shared/item", locals: {item: item} %>
    <% end %>
  </ul>
<% else %>
  <div>
    <p>一致する商品がありません。条件を変えて検索してみよう!</p>
  </div>
  <ul class='item-lists'>
    <% Item.all.each do |item| %>
      <%= render partial: "shared/item", locals: {item: item} %>
    <% end %>
  </ul>
<% end %>

以上で検索結果にあった商品が絞り出せます。
詳しい解説は後日しようと思います。