もふもふ技術部

IT技術系mofmofメディア

【Rails7】Hotwireで検索を実装する

Hotwireを使ってみる第二弾です!
今回は、検索結果をHotwireで表示するようにしてみます。
画面の全てを再描画する必要がないので、速度が上がるかもしれませんね!

下準備

  1. モデルを作る

    $ rails g model post
    

    20240813000000_posts.rb

    class CreatePosts < ActiveRecord::Migration[7.1]
     def change
       create_table :posts do |t|
         t.string :name
         t.timestamps
       end
     end
    end
    
  2. Gemをインストールする(ページネーションを使う場合)

    gem "kaminari"
    

実装する

  1. ルーティングを設定する
    config/routes.rb

    resources :posts, only: [:index]
    
  2. コントローラーの実装

    今回は name カラムをLIKE検索してみます。
    app/controllers/posts_controller.rb

    class PostsController < ApplicationController
      def index
        @posts = Post.where("name LIKE ?", "%#{search_params[:name]}%")
      end
    
      private
    
      def search_params
        params.fetch(:q, {}).permit(:name)
      end
    end
    
  3. viewsの実装
    app/views/posts/index.html.erb

    <%= form_with scope: :q, url: posts_path, method: :get, data: { turbo_frame: "posts" } do |f| %>
      <div>
        <%= f.text_field :name %>
        <%= f.submit "検索" %>
      </div>
    <% end %>
    <%= turbo_frame_tag 'posts' do %>
      <% @posts.each do |post| %>
        <div><%= post.name %></div>
      <% end %>
    <% end %>
    

これだけで、実装は終わりです。
検索すると、<%= turbo_frame_tag 'posts' do %> ブロックの中身だけ更新されます。

ページネーションを置きたい場合

ページネーションを置きたい場合も少しの修正だけで実装できます。

  1. コントローラーの修正

    @posts にページネーションの記述を追加します。
    app/controllers/posts_controller.rb

     @posts = Post.where("name LIKE ?", "%#{search_params[:name]}%").page(params[:page])
    
  2. viewsの修正

    ページネーションを置きたい場所に以下を追記します。
    ただし、<%= turbo_frame_tag 'posts' do %> ブロックの中に記述する必要があります。
    app/views/posts/index.html.erb

    <%= paginate @posts %>
    

URLを更新したい場合

今のままだと、ページを再読み込みした時に全ての検索条件や結果、ページがリセットされてしまいます。
検索項目が多いときに検索条件がリセットされるのは、とても使い勝手が悪いので、検索時にURLを更新して検索条件を保持するようにしてみます。

  1. コントローラーの修正

    検索条件をviewsで復元できるように @q に検索用パラメータを入れます。
    app/controllers/posts_controller.rb

     @q = search_params
    
  2. viewsの修正

    app/views/posts/index.html.erb

    1. 検索条件を復元します。

      <%= f.text_field :name, value: @q[:name] %>
      
    2. URLを更新するようにオプションを追加します。

      <%= turbo_frame_tag 'posts', data: { turbo_action: :advance } do %>
      

これで、URLを更新できるようになりました。
ページネーションを設置している場合も、現在のページがURLに含まれているのが確認できると思います。

終わり

1つの画面に複数の検索機能がついている場合などはとても強い気がしました。(そういう要件は滅多にないと思いますが。。。)
複数回読み込む必要がない部分や、読み込みに時間がかかる部分を除いた箇所を動的に変更する場合、Hotwireはかなり有用だと思いました!