おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

ransack という検索用の gem について

ransack はちょう便利な検索用 gem です。パラメータの name 属性で検索条件を定義できるので、多数の検索項目があってスクラッチで検索ロジックをつくるのがしんどいギョームwebアプリなどで絶大な威力を発揮します。

ただ一つの問題はドキュメントがとても貧弱だというところ。現状では細かい使い方について知りたければ、 デモアプリ を見ながら挙動を推察して行くしかないというお粗末さです…。でもやっぱり便利なので、なんとか情報をまとめて使えるようにしておきたい所存。気力が続かなかったので簡易的なまとめになりましたが載せておきます><

基本的な使い方については下記のリンク先をご覧ください。

custom predicates

独自の predicate を設定できます。下記をざっくり訳したものです。

Custom Predicates · ernie/ransack Wiki · GitHub

Ransack.configure do |config|
  config.add_predicate 'equals_diddly', # 独自 predicate の名前を指定
                       # arel の predicate を指定(例:eq, matches, etc)
                       :arel_predicate => 'eq',
                       # 渡した引数の差し替えができる。(デフォルト: 差し替えない)
                       :formatter => proc {|v| "#{v}-diddly"},
                       # 値を validate する。戻り値がfalse ならその値を検索には使わない。
                       # 下記がデフォルト。
                       :validator => proc {|v| v.present?},
                       # true にすると 'predicateの名前_all' と 'predicateの名前_any' の2つの predicate が追加される。
                       # その名の通り any/all 版 の predicate。デフォルト true。
                       :compounds => true,
                       # ここで指定されたカラムの型にキャストされて検索される
                       # (デフォルト: DBカラムの型)
                       :type => :string
end

使用例

4月30日までのデータを検索したい!みたいな検索条件を指定したときに、普通にやると4月30日の0時までが検索範囲になります。でも大抵の場合は4月30日の23時59分59秒までを検索範囲に含めたいですよね。そういうときに formatter をいじって

Ransack.configure do |config|
  config.add_predicate 'lteq_end_of_day',
                       :arel_predicate => 'lteq',
                       :formatter => proc {|v| v.end_of_day},
                       :compounds => false
end

などどするとよいです。

グループ化

ransack はデフォルトで AND 検索です。複数の検索条件を or で繋ぎたいときは、グループを作る必要があります。下記のようなパラメータを作って渡してやると、#name"hoge" または #nickname"fuga" なレコードを取得できます。

{:q => {:g => { '0' => { :m => 'or', :name_eq => 'hoge', :nickname_eq => 'fuga' }}}}

ソート

#sort_link メソッドでソート用のリンクを作ることができます。手動でソートする場合は #order も使えますが、パラメータを利用してソート順を切り替えるなら ransack の流儀に従う必要があります。そんなときは下記のようなパラメータを作って渡しましょう。

{:q => {:s => 'name asc'}}}