0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

【豆知識】Ransackとscope。検索機能について調べてみる。

Last updated at Posted at 2024-09-04

はじめに

検索機能を実装する時にRansackとscopeという機能があることを知りました。どちらも広く使用されているようなのでこの2つの機能を知ると同時に実際コードを入力するとなったらどんな感じになるのか、調べたことをまとめていきます。

環境

  • Windows, WSL
  • Docker
  • Ruby 3.2.3
  • Rails 7.1.3

Ransackscope の違いと使い分け

  1. Ransack:

    • Ransack は、複雑な検索フォームを簡単に実装するためのGemです。ユーザーがビュー(フォーム)から入力した複数の条件(例:複数のフィルターやソート)を扱う際に便利です。
    • モデル内で ransackable_attributesransackable_associations を定義することで、検索可能な属性や関連を指定できます。
  2. 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をうっかり忘れてしまったり。まだまだ使いこなせるには時間がかかりそうです。今日も今日とて奮闘中。
今回の記事をきっかけに検索機能について学ぶことがあれば幸いです。

0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?