「検索機能をつけたい!」
「検索ページを作るのではなく、検索窓として常にアプリ上部に出てくるようにしたい!」
といった時の対応方法です。
#はじめに
今回の前提は、
- 検索対象モデルがある。(今回はproductモデルと仮定する)
- 検索対象モデルのindexページがある。(例:app/view/products/index.html.erb)
- indexページを再利用して検索結果を表示させる。
としたいと思います。
#元コードイメージ
コントローラ
def index
@products = Product.all
end
view
<% render partial: 'products/product', collection: @products %>
collectionを使って各商品を表示させてます。
<%= product.name %>
<%= product.price %>
パーシャルを用いて各productの情報を表示させていきます。
※パーシャル名=変数名となるので注意。(例:_user.html.erbの場合は、user.nameとなる。)
だいたいこんな感じの状態のものを想定します。
#①Gemインストール
今回はransackというgemを使用します。
gem 'ransack'
記述したらbundle install
する。
#②検索機能の追加(コントローラの修正)
実は今回products_controller.rbは触りません。
products_controller.rbで検索機能を追加すると、検索”窓”として、どのページからでも使用することはできなくなるからです。
そのためapplication_controller.rbに機能追加していきます。
before_action :set_search
def set_search
@search = Product.ransack(params[:q])
@search_products = @search.result
end
#③検索窓の作成(viewの修正)
検索窓を作っていきます。
今回は特定のviewではなく、検索窓のような形で作成するので、application.html.erbなどに記入しましょう。
<%= search_form_for @search, products_path do |f| %>
<%= f.text_field :name_cont, placeholder: '名前を入力...' %>
<%= f.submit ("検索する") %>
<% end %>
ポイントは下記の部分です。
-
search_form_for
はform_for
のRansack版。 -
products_path
の記載によって、リダイレクト先はproductのindexページを指定している。 - 2行目に書いている
:name_cont
の記載によって、nameカラムに対して部分一致検索ができるようになる。
#④indexページでの条件分け(パーシャルへの変数の出し分け)
indexページを再利用するために、条件指定をします。
- 「検索窓→indexページ」の時には検索結果を表示させたい。(
@search_products
を表示させる。) - 上記以外の場合には、全ての商品を表示させたい。(
@products
を表示させる。)
<% if @search_products %>
<% render partial: 'products/product', collection: @search_products %>
<% else %>
<% render partial: 'products/product', collection: @products %>
<% end %>
これで、
@search_products
が存在する場合には、@search_products
がパーシャルに渡され、
@search_products
が存在しない場合には、@products
がパーシャルに渡されるので、indexページの再利用ができます。
おわりに
まだまだ駆け出しエンジニアなので、変な部分ありましたらドシドシコメント欲しいです!