Railsで検索用のGemといえばRansackが有名かと思います。Ransackって多機能ですが独自のルールとかが多くて、しばらく使ってないと使い方忘れちゃう。
そこで、今回は別のシンプルな検索用GemであるSearchCopを使ってみたので紹介しようと思います。
特徴
Ransackでは独自の記法を用いて検索条件を組み立てますが、複数のフィールドに対して複数の検索ワードでAND検索やOR検索を実現するのは以外と大変です(以下は昔自分が書いた記事です)。
SearchCopでは直感的かつ自然な書き方で、複雑な検索条件を組み立てることができます。
記述例
# 性・名・電話番号でのAND検索
User.search('田中 太郎 08012345678')
# メールアドレスに"gmail"が含まれており、登録が2015年あるいは2016年
User.search('email: gmail AND (created_at:2015 OR created_at:2016)')
サンプルコードで使うモデルの解説
例として、以下に示す二つのモデルが存在していると仮定します。
Userモデル
Userモデルは会員の情報を持つモデルで、以下のフィールドを含みます。
フィールド名 | 型 |
---|---|
id | integer |
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
User
とPost
は一対多の関係です。
使用方法
概要
仮に、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側の処理を自前で実装したい場合は、ベターな選択肢になるのではないでしょうか。