Railsアプリケーションで検索機能を実装する場合、最近はRansackを導入するケースが増えているのではないかと思います。
(Perfect Ruby on Railsでも取り上げられてましたしね。)

Ransackには2つのモードがあります。 Simpleモードでは、controllerとviewのインタフェースとしてsearchオブジェクトを使って簡単に検索フォームの実装ができます。 searchオブジェクトは通常のRailsアプリケーションにおいてmodelのインスタンスでcontrollerとviewのやりとりしているのを置き換える形になります。view側にはform_forに替わるsearch_form_forというヘルパーメソッドが用意されています。

今回はもうひとつのAdvancedモードを試してみたいと思います。

確認環境

Rails 4.2.1 ransack 1.6.6

モデルのscopeを検索条件にする

  • ransackを使って検索をする場合は、基本的にはモデルのもつカラム名に述語suffixを追加して検索条件を指定します。
    • titleの完全一致
1
  Post.ransack(title_eq: "It's a beautiful day")
  • titleの部分一致
1
  Post.ransack(title_cont: "It's a beautiful day")
  • しかしモデルに定義定義済みのscopeを検索条件として使いたくなる場合があります。その場合には、クラスメソッドransackable_scopesでransackの条件として利用するscopeを指定します。
1
2
3
4
5
6
7
8
9
class Post < ActiveRecord::Base
  belongs_to :blog

  scope :of_visible_blog, -> { includes(:blog).references(:blogs).merge(Blog.visible) }
  scope :title_of, ->(title) { where(title: title) }

  def self.ransackable_scopes(auth_object = nil)
    %i(of_visible_blog title_of)
  end

上記のように指定すると、次のようにscopeをransackの条件として利用することができるようになります。

1
2
3
  Post.ransack(of_visible_blog: true).result
  Post.ransack(title_of: "It's a beautiful day").result
  Post.ransack(of_visible_blog: true, title_of: "It's a beautiful day").result