はじめに
検索機能を実装する時にRansackとscopeという機能があることを知りました。どちらも広く使用されているようなのでこの2つの機能を知ると同時に実際コードを入力するとなったらどんな感じになるのか、調べたことをまとめていきます。
環境
- Windows, WSL
- Docker
- Ruby 3.2.3
- Rails 7.1.3
Ransack
と scope
の違いと使い分け
-
Ransack
:- Ransack は、複雑な検索フォームを簡単に実装するためのGemです。ユーザーがビュー(フォーム)から入力した複数の条件(例:複数のフィルターやソート)を扱う際に便利です。
- モデル内で
ransackable_attributes
とransackable_associations
を定義することで、検索可能な属性や関連を指定できます。
-
scope
:-
scope
は、シンプルで特定の条件に基づいたクエリをモデルに追加するための方法です。たとえば、特定のカラムに対して特定のパターンの検索を行う場合や、特定のレコードのみを取得する場合に使われます。 -
scope
は特定の用途に特化しており、モデルにカスタムメソッドとして定義され、ビューやコントローラから簡単に呼び出せます。
-
掲示板一覧の検索フォームを例に、使い分けを確認
Ransack使い方の例
まず、GemfileにRansackを追加する
# Gemfile
gem 'ransack'
次に、モデルにRansackの機能を使うための設定をする
# app/models/post.rb
class Post < ApplicationRecord
# ここに必要なスコープやバリデーションを追加
end
次に、コントローラでRansackを使って検索するコードを書く
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
# Ransackを使って検索オブジェクトを作成
@q = Post.ransack(params[:q])
# 検索結果を取得(重複を排除するオプション)
@posts = @q.result(distinct: true)
end
end
ビューでは、検索フォームを作成する
<!-- app/views/posts/index.html.erb -->
<%= search_form_for @q do |f| %>
<%= f.label :title_cont, "タイトルを検索" %>
<!-- title_contはタイトルに部分一致する条件を指定 -->
<%= f.text_field :title_cont %>
<%= f.submit "検索" %>
<!-- 検索ボタン -->
<% end %>
<% @posts.each do |post| %>
<p><%= post.title %></p>
<!-- 検索結果として表示されるタイトル -->
<% end %>
scope使い方の例
まず、モデルにscopeを追加する
# app/models/post.rb
class Post < ApplicationRecord
# titleに部分一致する条件を持つscopeを定義
scope :with_title, ->(title) { where("title LIKE ?", "%#{title}%") }
end
コントローラでは、scopeを使って検索するコードを書く
# app/controllers/posts_controller.rb
class PostsController < ApplicationController
def index
if params[:title].present?
# scopeを使って検索条件に一致する投稿を取得
@posts = Post.with_title(params[:title])
else
# パラメータがない場合は全ての投稿を取得
@posts = Post.all
end
end
end
ビューも少し変更する
<!-- app/views/posts/index.html.erb -->
<%= form_with url: posts_path, method: :get do |f| %>
<%= f.label :title, "タイトルを検索" %>
<!-- 検索フィールドのラベル -->
<%= f.text_field :title %>
<%= f.submit "検索" %>
<!-- 検索ボタン -->
<% end %>
<% @posts.each do |post| %>
<p><%= post.title %></p>
<!-- 検索結果として表示されるタイトル -->
<% end %>
おまけ:両方を使うこともある!?
どちらか片方だけの機能を持たせるのではなく、場合によっては両方の機能を使用することもあるんだとか。その理由については以下のようなものが挙げられるそうです。
-
柔軟性: プロジェクトの要件によっては、単純な部分一致検索(
LIKE
クエリ)を使う場面と、より複雑な検索フォームを提供する場面が混在することがあります。この場合、特定の条件に対してはシンプルなscope
を使い、複数の条件を組み合わせた検索には Ransack を使うことで、コードの柔軟性が向上します。 -
使い分け: たとえば、管理者がバックエンドで複雑なフィルタリングを行うために Ransack を使い、ユーザーインターフェイスでは簡単な検索機能だけが必要であれば、
scope
を使うことができます。
さいごに
私自身はransackを用いて作成を進めているのですが、ransackable_attributes
をうっかり忘れてしまったり。まだまだ使いこなせるには時間がかかりそうです。今日も今日とて奮闘中。
今回の記事をきっかけに検索機能について学ぶことがあれば幸いです。