Ruby on Rails

【Ruby on Rails5.2】Ransackの導入方法と使い方を教えます

・Ransackの導入方法
・Ransackの使い方

はじめに

Railsにて一覧画面を作成しましたが、追加機能として検索機能と並び順機能を追加しようと思い調べたらRansackが有名らしく、実際に使ってみて簡単だったので紹介したいと思います。

Ransack導入方法

Ransackの導入は難しくなく、Gemfileに追加してbunldeコマンドで実行します。

gem 'ransack'
bundle

これでRansackが使えます。

Ransack(シンプルモード)の実装方法

Ransackにはシンプルモードとアドバンスモードの2つがありますが今回はシンプルモードの紹介です。

今回、indexアクションにTaskテーブルを表示している想定です。

コントローラー

class TasksController < ApplicationController
  def index
    @q = Task.ransack(params[:q])
    @tasks = @q.result
  end
end

3行目の「params[:q]」に、後述するビューの検索文字列のパラメーターが渡されます。
Railsではパラメーターを絞る「Strong Parameters」を意識しますがRansackを使う場合は何でも受け取るようにしてモデル側で制御する方法を取ります。

4行目で検索結果を渡しています。

ビュー(Slim)

= 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'

1行目の「search_form_for」は「form_for」のRansack版です。
3,5行目の「:name_cont」はRansack特有の書き方です。
Ransackでは検索対象文字+特定の文字を設定することで検索条件を定義出来ます。

「:name_cont」の書き方だと「name」項目に対して「contains(含まれている)」検索を行います。
他の方法について後述参照ください。

確認

名称に適当な文字を入力して検索ボタンを押すと名称に含まれているもののみを表示します。
検索ボタンを押した後のSQLは下記のように、「”tasks”.”name” ILIKE ‘%te%’」とLIKE検索が行われています。

Task Load (0.5ms)  SELECT DISTINCT "tasks".* FROM "tasks" WHERE "tasks"."user_id" = $1 AND "tasks"."name" ILIKE '%te%' ORDER BY "tasks"."created_at" DESC  [["user_id", 1]]

その他の使い方

Contains検索以外の条件

Contains検索を行うときは「cont」を使うことで実装可能です。
それ以外の検索条件については代表的なものを抜粋します。

検索条件Ransack
一致eq
前方一致start
後方一致end
未満(<)lt
以下(<=)lteq
大きい(>)gt
以上(>=)gteq

ソート

Ransackはソートにも対応しています。
ソートは非常に簡単で、「sort_link」メソッドを使うことで対応出来ます。

table.table.table-hover 
    thead.thead-default 
        tr 
            th= sort_link(@q, :name)
            th= Task.human_attribute_name(:created_at)
            th= Task.human_attribute_name(:updated_at)
            th
    tbody 

4行目で「sort_link」メソッドを呼んでいます。
「sort_link」メソッド の中にはソート対象の項目を指定します。

参考記事

Ransackで簡単に検索フォームを作る73のレシピ
https://nekorails.hatenablog.com/entry/2017/05/31/173925