ActiveAdmin のフィルターでAND検索する

ActiveAdmin の filter では Ransack を利用することができる。

例えば以下のように定義してあげると、 nameカラムに対して LIKE検索することができる。

ActiveAdmin.register User do
fitler :name_matches

end

Ransackでは cont_allを利用することで、特定のカラムを複数の単語でAND検索することができる。

では、ActiveAdminでフォームにスペース区切りで複数の単語を入力した場合にnameカラムをAND検索したい場合はどうすれば良いだろうか

ActiveAdmin.register User do
fitler :name_cont_all

end

これまでの説明であれば、なんとなく上記のようなfilterを定義してあげるとできそうな気がする。 しかし上記のfilter を定義しフォームに「hoge fuga」を入力し検索を行うと以下のようなクエリが発行された。

SELECT COUNT(*) FROM (SELECT 1 AS one FROM `users` WHERE `users`.`deleted_at` IS NULL AND (`users`.`name` LIKE '%hoge fuga%') LIMIT 30 OFFSET 0) subquery_for_count

hoge fuga」を1つの単語としてLIKE検索しているのである。 これは Ransack側は単語を配列で渡されることを期待しているActiveAdminは素直に文字列で渡しているためである。

AND検索するためにはフォームに入力した文字列が、Rnsackに渡る前に配列に変換すれば良い。

例えば、以下のように before_action で文字列を配列に変換するなどが考えられる。

ActiveAdmin.register User do
  fitler :name_cont_all
  
  controller do
    before_action :adjust_search_params, only: :index
  
    private
  
    def adjust_search_params
      return if params[:q].nil? || params[:q][:name_cont_all].nil?
  
      params[:q][:name_cont_all] = params[:q][:name_cont_all].split(/[[:blank:]]+/)
    end
  end
end

ちなみにActiveAdmin側でスペース区切りで入力された単語を配列に分割するようにPull Requestが投げられているようだががマージには至っていない。

Support Ransacks _all and _any requests by kewubenduben · Pull Request #5465 · activeadmin/activeadmin · GitHub