LoginSignup
3
0

hotwireの学習①

Posted at

はじめに

この記事は、hotwireの学習についての備忘録です。

前回の記事の続き(importmap + bootstrap)です。
また、記事が長くなると思われるので、数回に分割する予定です
今回は、主に「Turbo Frames」に絞った内容です。

hotwireとは

他の記事に詳細が書かれてるので、この場ではさらっとした説明です。
HotwireはRails7からRailsのフロントエンドのデフォルトとなった技術です。
また、複数の機能を統合した相称の名前となります。

  • Hotwire
    • Turbo
      • Turbo Drive    ・・・画面描写を早くする
      • Turbo Frames  ・・・部分差し替えを行う(主にgetで利用)
      • Turbo Streams  ・・・部分差し替えを行う(主にget以外で利用)
    • Stimulus      ・・・rails専用のJS

todo作成

基本画面を作成

コマンド
docker compose run --rm app bundle exec rails generate scaffold todo content:string complete:boolean

テストデータを登録するseedファイルを準備します

app/db/seeds.rb
Todo.create(
  [
    {content: "柳田 政年" , complete: 0},
    {content: "佐野 護" , complete: 0},
    {content: "小松 純典" , complete: 0},
    {content: "堀川 陽子" , complete: 0},
    {content: "堀川 武士" , complete: 0},
    {content: "松原 竹義" , complete: 0},
    {content: "山崎 詔勝" , complete: 0},
    {content: "大内 武俊" , complete: 0},
    {content: "藤村 広重" , complete: 0},
    {content: "白川 芳尚" , complete: 0},
    {content: "大塚 美砂" , complete: 0},
    {content: "茂木 幸郎" , complete: 0},
    {content: "辻 和広" , complete: 0},
    {content: "東 茂俊" , complete: 0},
    {content: "豊田 世弥" , complete: 0},
    {content: "笠原 永寿" , complete: 0},
    {content: "浅井 陽一郎" , complete: 0},
    {content: "吉沢 祐子" , complete: 0},
    {content: "中野 貢太郎" , complete: 0},
    {content: "奥野 貢太郎" , complete: 0},
    {content: "竹内 芳伸" , complete: 0},
    {content: "花田 十四夫" , complete: 0},
    {content: "西川 重文" , complete: 0},
    {content: "後藤 一樹" , complete: 0},
    {content: "古田 早葉子" , complete: 0},
    {content: "坂井 裕仁" , complete: 0},
    {content: "中野 昌光" , complete: 0},
    {content: "堀江 茂也" , complete: 0},
    {content: "小野 理江" , complete: 0},
    {content: "徳田 真里" , complete: 0},
    {content: "古谷 督彦" , complete: 0},
    {content: "田代 健生" , complete: 0},
    {content: "古谷 常一" , complete: 0},
    {content: "藤村 克三" , complete: 0},
    {content: "横山 琢司" , complete: 0},
    {content: "浅野 元信" , complete: 0},
    {content: "古谷 政年" , complete: 0},
    {content: "小田 三佐男" , complete: 0},
    {content: "村瀬 尭道" , complete: 0},
    {content: "武井 恵治" , complete: 0},
    {content: "土屋 孝次" , complete: 0},
    {content: "大場 令" , complete: 0},
    {content: "久保 友良" , complete: 0},
    {content: "大平 美津枝" , complete: 0},
    {content: "山岸 時司" , complete: 0},
    {content: "下田 美里" , complete: 0},
    {content: "岡 敬志" , complete: 0},
    {content: "森田 道和" , complete: 0},
    {content: "白川 恵" , complete: 0},
    {content: "松本 俊憲" , complete: 0},
    {content: "秋田 秋代" , complete: 0},
    {content: "安井 勝英" , complete: 0},
    {content: "藤川 敬生" , complete: 0},
    {content: "谷川 元三" , complete: 0},
    {content: "山本 興亜" , complete: 0},
    {content: "小松 良司" , complete: 0},
    {content: "竹下 勤" , complete: 0},
    {content: "新田 酉蔵" , complete: 0},
    {content: "竹本 幸四郎" , complete: 0},
    {content: "野崎 慶太郎" , complete: 0},
    {content: "古谷 朋子" , complete: 0},
    {content: "大森 裕子" , complete: 0},
    {content: "荻野 生三" , complete: 0},
    {content: "丹羽 重三郎" , complete: 0},
    {content: "坂田 安民" , complete: 0},
    {content: "堀 十四夫" , complete: 0},
    {content: "奥山 義将" , complete: 0},
    {content: "小出 成男" , complete: 0},
    {content: "馬場 育雄" , complete: 0},
    {content: "高瀬 夕子" , complete: 0},
    {content: "福原 和久" , complete: 0},
    {content: "大沢 允彦" , complete: 0},
    {content: "本間 多栄子" , complete: 0},
    {content: "細川 敬" , complete: 0},
    {content: "植田 麻紀" , complete: 0},
    {content: "千田 三重子" , complete: 0},
    {content: "緒方 裕恵" , complete: 0},
    {content: "福岡 美緒" , complete: 0},
    {content: "野田 常次" , complete: 0},
    {content: "藤川 真樹" , complete: 0},
    {content: "横井 紀子" , complete: 0},
    {content: "堀内 美里" , complete: 0},
    {content: "本間 十四夫" , complete: 0},
    {content: "松山 勝行" , complete: 0},
    {content: "福永 優紀" , complete: 0},
    {content: "関根 洋昌" , complete: 0},
    {content: "富田 忠之" , complete: 0},
    {content: "平山 勝司" , complete: 0},
    {content: "田上 恵治" , complete: 0},
    {content: "増田 雅則" , complete: 0},
    {content: "古谷 俊郎" , complete: 0},
    {content: "安部 善二" , complete: 0},
    {content: "土田 十四夫" , complete: 0},
    {content: "池上 玲子" , complete: 0},
    {content: "福井 純隆" , complete: 0},
    {content: "大石 梨華" , complete: 0},
    {content: "尾崎 聡" , complete: 0},
    {content: "島田 利克" , complete: 0},
    {content: "堀内 唯" , complete: 0},
    {content: "福本 美津枝" , complete: 0},
  ]
)

DB構築及びテストデータを登録

docker compose run --rm app bundle exec rails db:drop db:create db:migrate db:seed

全体的に淵ギリギリに表示されるのは微妙なので、少しマージンを設定しときます

app/app/views/layouts/application.html.erb
<!DOCTYPE html>
<html>
  <head>
    <title>App</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
  </head>
  
-  <body>
+  <body class="px-4">
    <%= yield %>
  </body>
</html>

トップページに、作成したtodoへのリンクを配置しておきます

app/app/views/top/index.html.erb
<h1>Top#index</h1>
<p>Find me in app/views/top/index.html.erb</p>

<button type="button" class="btn btn-primary">Primary</button>
<button type="button" class="btn btn-secondary">Secondary</button>
<button type="button" class="btn btn-success">Success</button>
<button type="button" class="btn btn-danger">Danger</button>
<button type="button" class="btn btn-warning">Warning</button>
<button type="button" class="btn btn-info">Info</button>
<button type="button" class="btn btn-dark">Dark</button>

<button type="button" class="btn btn-link">Link</button>


<div class="btn-group">
  <button type="button" class="btn btn-danger dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
    Action
  </button>
  <ul class="dropdown-menu">
    <li><a class="dropdown-item" href="#">Action</a></li>
    <li><a class="dropdown-item" href="#">Another action</a></li>
    <li><a class="dropdown-item" href="#">Something else here</a></li>
    <li><hr class="dropdown-divider"></li>
    <li><a class="dropdown-item" href="#">Separated link</a></li>
  </ul>
</div>

+ <hr>
+ <%= link_to 'todo', todos_path, class: 'btn btn-primary' %>

この時点でのトップページはこんな感じになります
image.png

indexの修正

画面は、昔のテーブル形式にしておきます

app/app/views/todos/index.html.erb
<h1>Todos</h1>
<%= link_to "New todo", new_todo_path %>
<table class="table table-bordered mt-2">
  <thead>
    <td>ID</td>
    <td>Content</td>
    <td></td>
  </thead>
  <tbody>
    <% @todos.each do |todo| %>
      <%= render todo %>
    <% end %>
  </tbody>
</table>
app/app/views/todos/_todo.html.erb
<tr>
  <td>
    <%= todo.id %>
  </td>
  <td>
    <%= todo.content %>
  </td>
  <td>
    <div class="d-flex justify-content-end">
      <%= link_to "Show", todo, class: "btn btn-sm btn-outline-primary me-2" %>
      <%= link_to "edit", edit_todo_path(todo), class: "btn btn-sm btn-outline-primary me-2" %>
      <%= button_to "Destroy", todo, method: :delete, data: { turbo_confirm: '本当に削除していいですか?' } , class: "btn btn-sm btn-outline-danger" %>
    </div>
  </td>
</tr>

画面確認

image.png

ページネートを追加

app/Gemfile
gem "kaminari"
gem 'bootstrap4-kaminari-views'
コマンド
docker compose build --no-cache
docker compose run --rm app bundle install
app/app/controllers/todos_controller.rb
  # GET /todos or /todos.json
  def index
-   @todos = Todo.all
+   @todos = Todo.all.page(params[:page]).per(10)
  end
app/app/views/todos/index.html.erb
<h1>Todos</h1>
<%= link_to "New todo", new_todo_path %>
<table class="table table-bordered mt-2">
  <thead>
    <td>ID</td>
    <td>Content</td>
    <td></td>
  </thead>
  <tbody>
    <% @todos.each do |todo| %>
      <%= render todo %>
    <% end %>
  </tbody>
</table>
+ <%= paginate @todos, theme: 'twitter-bootstrap-4'%>

画面確認

image.png
見た目はこんな感じになります

1709014517.gif
動きとしても従来通りのURLにページ番号が乗ってる状態です

image.png
コンソールでは、こんな感じに表示されており、平均速度35~45msという感じでした

コレクションキャッシュを使ってみる

app/app/views/todos/index.html.erb
<h1>Todos</h1>
<%= link_to "New todo", new_todo_path %>
<table class="table table-bordered mt-2">
  <thead>
    <td>ID</td>
    <td>Content</td>
    <td></td>
  </thead>
  <tbody>
-     <% @todos.each do |todo| %>
-       <%= render todo %>
-     <% end %>
+     <%= render partial: 'todo', collection: @todos, cached: true %>
  </tbody>
</table>
<%= paginate @todos, theme: 'twitter-bootstrap-4'%>

画面確認

1709014618.gif

image.png
レンダリングが少し早くなって、平均速度25~35msという感じでした

Turbo Frames

app/app/views/todos/index.html.erb
<h1>Todos</h1>
<%= link_to "New todo", new_todo_path %>
+ <%= turbo_frame_tag "todos-table" do %>
  <table class="table table-bordered mt-2">
    <thead>
      <td>ID</td>
      <td>Content</td>
      <td></td>
    </thead>
    <tbody>
      <%= render partial: 'todo', collection: @todos, cached: true %>
    </tbody>
  </table>
  <%= paginate @todos, theme: 'twitter-bootstrap-4'%>
+ <% end %>

画面確認

1709015008.gif
URLを確認するとURLが変わらずSPA化できてます!

image.png
応答速度を確認したところ、15~25msという感じでした

最後に

今回はここまでにします。
Turbo Framesを使うことで、簡単にSPA化できてることに驚いています。
次回は、引き続きTODOの更新関係を手掛け、Turbo Streamsについて学んでいきます

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