takumiのエンジニア技術ブログ

takumiのエンジニア技術ブログ

未経験からエンジニアを目指しています!技術定着の為にこのブログにアウトプットしていきます!気軽にコメント等いただけるとありがたいです!

タスク一覧画面に検索機能を実装する(ransack)

f:id:golikyua:20190923173318j:plain

 

検索機能の実装について勉強したので、アウトプットしたいと思います!

 

目標

 

「タスク一覧画面に検索機能を追加」

 

やること

 

・Ransackのインストール

・名称による検索機能の実装

・登録日時による検索機能の実装

・検索条件を絞る

 

 

本題

 

・Ransackのインストール

Gemfileに「gem 'ransack'」を入力し、bundlerで「bundle」を実行。

 

・名称による検索機能の実装

ransackをインストールするとransackメソッドがモデルに追加される。

 

ransackメソッドを使用して、コントローラを修正する。

def index
@q = current_user.tasks.ransack(params[:q]) @tasks = @q.result(distinct: true).recent ... end

 

タスク一覧画面に検索フォームを作成する。

ranscakによりsarch_form_forという検索フォームを作成されるヘルパーが提供される!

h1 タスク一覧

= search_form_for @q, class: 'mb-5' do |f|
  .form-group.row
    = f.label :name_cont, '名称', class: 'col-sm-2 col-form-label'
    .col-sm-10
      = f.search_field :name_cont, class: 'form-control'
 .form-group
  = f.submit class: 'btn btn-outline-primary' = link_to '新規登録', new_task_path, class: 'btn btn-primaty mb-3'

※ranscakを利用する際は、検索フィールドの名前を一定のルールに従ってつける。

今回は名称に「検索フォームで入力した文字が含まれている」という検索を実現したいので「name_cont」という名前をつける。

 

検索時のSQLを調べると、PostgreSQLのILIKE(大文字と小文字の区別をしない)が使われていた。これは検索フィールドの名前を「name」にした結果である。

 

また「_cont」は、検索文字列を含むものを検索するransackが用意したマッチャー。

 

よって「name_cont」を検索フォームの名前にすることで、入力した文字列を含むタスクを検索できるようになる。

 

・登録日時による検索

タスク一覧の検索フォームに登録日時のフィールドを追加する。

h1 タスク一覧

= search_form_for @q, class: 'mb-5' do |f|
  .form-group.row
    = f.label :name_cont, '名称', class: 'col-sm-2 col-form-label'
    .col-sm-10
      = f.search_field :name_cont, class: 'form-control'
  .form-group.row
    = f.label :created_at_gteq, '登録日時', class: 'col-sm-2 col-form-label'
    .col-sm-10
      = f.search_field :created_at_gteq, class: 'form-control'
  .form-group
    = f.submit class: 'btn btn-outline-primary'

= link_to '新規登録', new_task_path, class: 'btn btn-primary mb-3'

登録日時検索フィールドで使用した_gteqは、greater than or equalの略で、「入力した値より大きいか同じ」なものを検索する。

日時の場合は、「同じ日にちかそれより未来の日にち」を検索する。

 

登録日時の検索後のSQLでは、比較演算子の「>=」が使われている!

 

・検索条件を絞る

どうやらユーザーが意図的にパラメータを加工すると、他のカラムを使った検索ができてしまうらしい。

それを防ぐために、検索結果に制限をかける。

app/models/task.rb

class Task < ApplicationRecord


def self.ransackable_attributes(auth_object = nil)
  %w[name created_at]
end

def self.ransackable_associations(auth_object = nil)
  []
end

...

end

 ransackable_attributesで、検索対象にすることを許可するカラムを指定する。

nameとcreate_atを指定することで、他のデータを検索フォームに入力しても無視される。

 

ransackable_associationsは、検索条件に含める関連を指定できる。

このメソッドを空の配列を返すようにオーバーライドすることで、検索条件に意図しない関連を含めないようにすることができる。

 

 

まとめ

・ransackをインストール

・ransackメソッドを使って、コンソールの編r集

・search_form_foを使い、ビューに検索フォームを作成する。

・rasackable_attributes, ransackable_associationsメソッドで検索条件をつける。

 

ransackめちゃめちゃ便利!!