Edited at

検索用Gem"SearchCop"の紹介

More than 1 year has passed since last update.

Railsで検索用のGemといえばRansackが有名かと思います。Ransackって多機能ですが独自のルールとかが多くて、しばらく使ってないと使い方忘れちゃう。

そこで、今回は別のシンプルな検索用GemであるSearchCopを使ってみたので紹介しようと思います。

https://github.com/mrkamel/search_cop


特徴

Ransackでは独自の記法を用いて検索条件を組み立てますが、複数のフィールドに対して複数の検索ワードでAND検索やOR検索を実現するのは以外と大変です(以下は昔自分が書いた記事です)。

ransackを使った複数ワードによるAND検索の実装

SearchCopでは直感的かつ自然な書き方で、複雑な検索条件を組み立てることができます。

記述例

# 性・名・電話番号でのAND検索

User.search('田中 太郎 08012345678')

# メールアドレスに"gmail"が含まれており、登録が2015年あるいは2016年
User.search('email: gmail AND (created_at:2015 OR created_at:2016)')


サンプルコードで使うモデルの解説

例として、以下に示す二つのモデルが存在していると仮定します。


Userモデル

Userモデルは会員の情報を持つモデルで、以下のフィールドを含みます。

フィールド名

id
integer

email
string

first_name
string

last_name
string

age
integer

created_at
date

class User < ApplicationRecord

has_many :posts
end


Postモデル

Postモデルは投稿内容を持つモデルで、以下のフィールドを含みます。

フィールド名

id
integer

user_id
integer

title
string

message
text

created_at
date

class Post < ApplicationRecord

belongs_to :user
end

UserPostは一対多の関係です。


使用方法


概要

仮に、Userに検索機能をつけたい場合、Userのモデルファイルに以下の記述を追加します。

class User < ApplicationRecord

include SearchCop
has_many :posts

search_scope :search do
attributes :email, :first_name, :last_name, :age, :created_at
attributes post: ['posts.title', 'posts.message']
end
end

上記のコードを追加することで、Userモデルでsearchというスコープが使えるようになります。

User.search('Ruby')

これだけの記述で、Userモデルの全フィールド及び関連テーブルであるPostモデルのフィールドに対して、"Ruby"という文字列でLIKE検索が走ります。


検索フィールドの指定

前述した例では全てのフィールドを指定しましたが、検索条件として特定のフィールドのみを指定することも可能です。また、検索スコープに名前を付けて、複数定義することもできます。

search_scope :name_search do

attributes :first_name, :last_name, created_at
end

search_scope :post_search do
attributes post: ['posts.title', 'posts.message']
end

検索時に検索対象のフィールドを指定することも可能です。ここで指定しない場合は、全フィールドが検索されます。

# last_nameのみを検索

User.search('last_name:松本')

日付や整数に対して、範囲指定することもできます。

# 2017年に登録されたもののみ

User.search('created_at:2017')

# ageが20より上
User.search('age > 20')

そして、これらの条件をANDやORで容易に組み合わせることもできます。

User.search('(last_name:松本 OR age > 20) AND created_at:2017')


FullText Indexへの対応

SearchCopはデフォルトでLIKE検索が実行されるため、レコード数やフィールドのサイズによっては、検索に時間がかかることが予想されます。

SearchCopでは、FullText Indexに標準で対応しています。

search_scope :search do

attributes message: 'posts.message'
options :message, type: :fulltext
end

ここでは、FullText Indexに関する詳細な説明は省きます(すみません、ここは試してないです・・・)。


終わりに

Ransackが、controllerやviewを含めた、サービスに組み込むための検索機能全般を提供しているのに対して、SearchCopはモデルを検索するためのインターフェースのみに特化ている感じでしょうか。controllerやview側の処理を自前で実装したい場合は、ベターな選択肢になるのではないでしょうか。