37
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

検索用Gem"SearchCop"の紹介

Last updated at Posted at 2017-06-04

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

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

特徴

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側の処理を自前で実装したい場合は、ベターな選択肢になるのではないでしょうか。

37
30
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
37
30

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?