はじめに
皆さん、お疲れ様です。
今回、"Ransack" Gem を用いた検索機能の実装を行なっている際にとあるエラーが発生し、数時間溶かしてしまったので、備忘録として技術記事を作成しました。
もし同じエラー内容が発生している方は、是非今回の記事内容を解決の糸口として活用していただければと思います...!
概要
今回、《Ruby on Rails》を用いた投稿掲示板アプリにて、検索機能を"Ransack" Gem を用いて実装していました。
検索機能の実装内容としては、 『ヘッダー部分に投稿に関する検索フォームを実装、検索を行うと投稿一覧画面に検索フォームに入力したワードに関する投稿のみを表示する。』 と言うシンプルな検索機能です。
しかし、この検索機能を実装後に実際に検索を掛けて投稿を絞った後、各投稿の詳細画面にアクセスしようとしたところ...
《ArgumentError in Posts#index No Ransack::Search object was provided to search_form_for!》
と言うエラーが発生してしまいました...!
今回は、発生した上記エラーがどういった内容なのかと、その対処方法について纏めさせていただきました。
プログラミング初学者なりに纏めた記事になっておりますので、内容等に誤り等がある場合がございますのでご了承下さい。
もし誤りに気づかれた際は、コメント等でご教授いただけると助かります🙇♂️
Ransack Gem とは?
まず、エラー内容の説明を行う前に "Ransack" Gem について軽く説明をしたいと思います。
"Ransack" は 《Ruby on Rails》 のアプリケーションで、高度な検索フォームやソート機能を簡単に実装するためのGemです。
Ransackの主な特徴としては、以下の4つになっています。
1. シンプルな検索フォームの生成
Ransackを使用する事で、検索フォームを簡単に生成できる。特に、複雑な検索条件やソート条件を持つフォームを簡単に作成することができるようになる。
2. 高度な検索クエリのサポート
Ransackは、「AND/OR条件」「範囲検索」「関連テーブルの検索」など、多くの高度な検索クエリをサポートしている。
3. ソート機能
Ransackを使用する事で、結果のソート順を簡単に指定することができる。
4. カスタム検索条件
必要に応じて、カスタムの検索条件やソート条件を定義することができる。
上記の特徴の通り、"Ransack"はその名前の由来となる"ransack"(徹底的に探す)のように、高度な検索やソートの機能を提供してくれる強力なGemです。そのため、多くのRailsアプリケーションで検索機能の実装に利用されています。
💡Gemの導入方法についてはこちらから⇩
今回発生したエラーについて
では、"Ransack"の説明が終わったところで、今回発生したエラーについて説明をしていきたいと思います。
今回発生したエラーは...《ArgumentError in Posts#index No Ransack::Search object was provided to search_form_for!》
このエラーは、search_form_for
ヘルパーを使用して検索フォームを作成しようとしたときに、適切なRansack::Search
オブジェクトが提供されなかった場合に発生します。
なぜこのようなエラーが発生したのか?
では、なぜこのようなエラーが発生したのか?
そもそも今回の検索機能については、検索フォームをヘッダー部分に実装するようにしていました。
つまり、search_form_for
ヘルパーをviewのヘッダーファイルで使用していた、という事になります。
<%= search_form_for @q, url: posts_path, class: "d-flex" do |f| %>
<%= f.search_field :title_or_body_cont, class: "form-control me-2", placeholder: "投稿" %>
<% end %>
search_form_for
ヘルパーをヘッダー部分に使用しているという事は、「その検索フォームはアプリケーションのどのページにアクセスしても表示される」 という事になります。
つまり、ヘッダーが表示されるすべてのページで Ransack::Search
オブジェクトが利用可能である必要があるんです。
しかし、今回Ransack::Search
オブジェクトを生成するコードを、Posts#index
でしか記述していませんでした...。
つまり、Postsコントローラーのindexアクション内でのみRansack::Search
オブジェクトを生成しているため、他のページではRansack::Search
オブジェクトが存在しない状態になっていました...。
def index
@q = Post.ransack(params[:q])
@posts = @q.result(distinct: true).order(created_at: :desc).page(params[:page]).per(10)
end
そのため、投稿詳細画面にアクセスしようとしても、showアクション内にRansack::Search
オブジェクトが存在しない為にエラーが発生していました。
対処方法
では、このような場合どのように対処すれば良いのか?
簡単です。
全てのアクションでRansack::Search
オブジェクトを生成すれば良いのです!
今回発生したエラーの原因は...
『ヘッダーが表示されるすべてのページでRansack::Search
オブジェクトが利用可能である必要があるが、実際はindexアクション内にしかRansack::Search
オブジェクトが存在していなかった。』
なので、全てのアクションでRansack::Search
オブジェクトを生成すれば問題ありません。
しかし、全てのアクションにオブジェクトを生成するコードを記述するのはかなり手間ですし、コードの見た目も綺麗ではありません...。
なので、コントローラー全体に反映されるようapplication_controller.rb
に記述していくようにします。
class ApplicationController < ActionController::Base
before_action :set_search
def set_search
@q = Post.ransack(params[:q])
@posts = @q.result(distinct: true).order(created_at: :desc).page(params[:page]).per(10)
end
end
注意点
この際、postsコントローラーの各アクションが実行される前にRansack::Search
オブジェクトを生成する必要があるので、必ずオブジェクトを生成するメソッドset_search
をbefore_action
で呼び出すようにしましょう。
上記のように記述することで、postsコントローラーの各アクションにRansack::Search
オブジェクトが生成されるようになるので、エラーは発生しなくなります。
まとめ
ある特定の画面でのみ検索フォームを実装する場合は、その画面に対応するコントローラーのアクション内にRansack::Search
オブジェクトを生成しておけば問題ありません。
しかし、複数画面内に検索フォームを実装する場合は、各画面ごとに対応するアクション内全てにRansack::Search
オブジェクトを生成しておく必要があります…!
私は、ヘッダーに検索機能を実装するのが今回初だったので、いつもの要領でコードを記述してしまいこのようなエラーが発生してしまいました…😭
皆さんも、検索フォームを複数画面に実装する場合はお気をつけ下さい...!🙇♂️