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?

ransacker を利用したカスタム検索機能の実装

Posted at

ransacker を利用したカスタム検索機能の実装

この記事では、Rails アプリケーションにおいて、テーブルに直接存在しない計算結果や集計値 を検索条件として利用する方法をご紹介します。具体的には、Book モデルに関連付けられた Post の件数を基に検索を行う例を取り上げます。


はじめに

Rails で検索機能を実装する際、ransackという Gem を利用しました。

そこで、テーブルのカラムにない値で検索をする必要があり、それを達成するためにはransackerを利用すればできるということを学びました。学んだ内容を記事にしたいと思います。

ちなみに、ransackで検索機能をつくるのは以下の記事を参考にしました。

参考記事


環境

  • Ruby: 3.2.4
  • Ruby on Rails: 7.1.2

ransacker とは?

ransacker の目的

Ransack は Rails アプリケーションに柔軟な検索機能を提供する Gem です。しかし、標準状態ではテーブルに存在するカラムのみが検索対象となります。

そこで、ransacker を利用することで、以下のようなケースに対応可能です。

  • 計算結果や集計値を検索条件に含めたい場合
  • テーブルのカラム以外のデータを検索に利用したい場合

この記事では、Book に関連する Post の件数(投稿数)を検索対象とする例を取り上げます。


データベースの構成

今回のサンプルでは、BookPost1対多 (has_many/belongs_to) の関係になっています。

app/models/book.rb

class Book < ApplicationRecord
  has_many :posts, dependent: :destroy
end

app/models/post.rb

class Post < ApplicationRecord
  belongs_to :book
end

カスタム検索条件の実装

モデル内に ransacker メソッドを定義することで、仮想的な属性を検索条件として追加できます。以下のコード例では、posts_count という仮想属性を定義し、Book に紐付く Post の件数を取得する SQL サブクエリを利用しています。

# app/models/book.rb

class Book < ApplicationRecord
  has_many :posts, dependent: :destroy

  ransacker :posts_count do
    Arel.sql('(
      SELECT COUNT(posts.id)
      FROM posts
      WHERE posts.book_id = books.id
    )')
  end
end

この定義により、ransack を使った検索時に posts_count を条件として指定できるようになります。たとえば、投稿数が特定の数以上の書籍を抽出するなどの検索が可能です。


おわりに

今回の実装例では、SQL のサブクエリを利用して仮想属性を定義しましたが、データ量が増加するとパフォーマンス面で課題が出る可能性があります。

そのため、将来的に投稿数での検索を多用する場合は、posts_count カラムを用意し、投稿作成や削除時にカウントを更新する などの対応が良さそうです。

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?