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] %>
- URLを更新するようにオプションを追加します。
<%= turbo_frame_tag 'posts', data: { turbo_action: :advance } do %>
これで、URLを更新できるようになりました。
ページネーションを設置している場合も、現在のページがURLに含まれているのが確認できると思います。
終わり
1つの画面に複数の検索機能がついている場合などはとても強い気がしました。(そういう要件は滅多にないと思いますが。。。)
複数回読み込む必要がない部分や、読み込みに時間がかかる部分を除いた箇所を動的に変更する場合、Hotwireはかなり有用だと思いました!