rails 4でransackを使った検索機能を実装した
すごく簡単に検索機能を実装できるというransack
。
metasearch
というGemの後継らしい。
ちょうど検索を実装する案件があったので、試しに使ってみた。
流れ
前提
- 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
単純に入力値と等しい項目を探したい場合は、name
とeq
と続けて記述し、関連テーブル
のカラムに対して検索したい場合は、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