kame's engineer note

技術関連のメモをブログに記録していく

rails 4でransackを使った検索機能を実装した

すごく簡単に検索機能を実装できるというransack
metasearchというGemの後継らしい。
ちょうど検索を実装する案件があったので、試しに使ってみた。

流れ

  • ransack導入
  • searchメソッド(DSL)の実装
  • ransackable_scopesで柔軟な検索実装

前提

  • Authorモデルの検索一覧ページとする
  • 例としてモデルの構成は下記のようにする
Author -has_many-> Post

authors_table
- name
- category

posts_table
- title
- author_id
- entry

ransack導入

Gem 'ransack'

gemからインストールする。

https://github.com/activerecord-hackery/ransack

searchメソッド(DSL)の実装

controller.rb

def hoge
  @q = Author.ransack params[:q]
  @authors = @q.result(distinct: true).includes(:posts)
end

パラメータをransackに投げてあげて、resultで結果を取得する。
今回は関連テーブルがあるので、includesで指定してあげる。

view.slim.html

= search_form_for(@q, url: hoge_path, method: :get) do |f|
  .div
    = f.label :name
    = f.search_field :name_eq
  .div
    = f.label :posts
    = f.search_field :posts_title_eq
  .div
    = f.label :category
    =f.collection_check_boxes :category_in, category_list, :id, :name, {checked:@q.categgory} do |b|
      - b.label {b.check_box + b.text}

基本的には項目名 + 条件でパラメータを渡してあげれば、その条件にそった検索を実行してくれる。
以下のQita記事に簡単に条件がまとめられているので参考にするとよい。
http://qiita.com/nysalor/items/9a95d91f2b97a08b96b0

単純に入力値と等しい項目を探したい場合は、nameeqと続けて記述し、関連テーブルのカラムに対して検索したい場合は、posts_title_eqのようカラムと条件に加え、関連テーブル名を先頭に記述する。
また、チェックボックス等で選択した複数の項目を検索したい場合は、inを使うと便利だ。
あとはフリーワード検索なんか↓のように描くことも可

name_or_category_or_posts_title_or_posts_entry_cont

他にも色々な条件がパラメータの書き方を変えるだけで検索可能となる。

ransackable_scopesで柔軟な検索実装

複雑な検索をしたい場合は、scope(あるいはmethod)を定義することで実現可能となる。

author.rb

# custom scope
scope :custom_scope, -> (boolean=true) {
  joins(:posts).where(active: boolean)
}

private

# for ransack scope
def self.ransackable_scopes(auth_object=nil)
  %i(custom_scope)
end

view.slim.html

= search_form_for(@q, url:hoge_path,method: :get) do |f|
  .div
    = f.label :custom_scope
    = f.search_field :custom_scope

model内にscopeの実装を記述し、そのscope名をransackable_scopesにシンボルとして定義してあげる。
あとは定義したscope名をinputメソッドのオプションに記述するだけでよい。

ひとこと

そこまで複雑な検索機能を実装する必要性がないのであれば、自分でゴリゴリかくよりもいいかもしれない。 というか、結構複雑な検索でもscopeとか使えば実装できるし、特に縛りもないのでコレ一本でやっていけるかもですね。

参考URL

https://github.com/activerecord-hackery/ransack
http://qiita.com/ruzia/items/f6003547ca18377a1508
http://qiita.com/nysalor/items/9a95d91f2b97a08b96b0