Hotwire キャッチアップ体験談
こんにちは! 万葉でエンジニアをしている koheitakahashi です。
万葉は Hotwire を推していきます! でご紹介したように、弊社では Hotwire を推進するために情報発信を行っています。今回は、私が Hotwire をどのようにキャッチアップしたのかと、その過程で感じたことをご紹介します。
これから Hotwire をキャッチアップされる方が、この記事を読んで「Hotwire をキャッチアップする道筋がイメージできる」状態になることを目指しています。お役に立てば幸いです。
どのようにキャッチアップしたのか
キャッチアップのためにやったことは大きく分けて以下の2つです。それぞれ、詳しく書いていきます。
1. 資料を読んで概要・背景を理解する
まずは、Hotwire の概観を掴むことを意識して、いろいろな資料を読みました。
一番最初に読む記事としては、「Hotwire の全体像」「Hotwire でどういうメリットが得られるのか」を大づかみに理解できる、次の2つをおすすめします。
また、以下の記事は、Rails7 や Hotwireの背景になっているRailsの作者DHHの思想を知ることができて参考になりました。この背景を知ったことで、Stimulusの特徴や使い方を把握しやすくなったと感じています。
2. 手を動かして実感する
当然のことですが、参考資料を読んだだけでは、Hotwireを使ったコードをスラスラ書くことはできませんでした。そこで、以下の記事を「写経」しました。
※「写経」・・・コード例を真似て書き、動かしてみること
こちらの記事はチュートリアルとして、とても分かりやすい記事です。表面的な使い方にとどまらず、内部の仕組みまで言及されていて、理解しやすいと感じました。
次に、以下のチュートリアルにも目を通しました。
Hotrails - Learn modern Ruby on Rails with Hotwire
やや細かい話になってしまいますが、こちらの記事の後半部分には、以下のような実践的な内容が書かれており、参考になりました。
特定のユーザーにブロードキャストするにはどうするか
ネストした Frames の場合にどう実装するか
その後、自分が個人開発しているアプリで Hotwire を実際に使ってみました。このアプリは「カップル用の割り勘アプリ」で、月ごとに支出を登録でき、その月の2人の支払金額を分かりやすくしてくれます。
このアプリで、以下のような順番で Hotwire を試しました。
Turbo Frames を使って、インラインで支出の登録が行えるようにした
Trubo Streams を使って、登録した支出が画面遷移なしで一覧に表示されるようにした
Turbo Streams(WebSocket)を使って、複数ユーザーが同時的に一覧画面の変更を見られるようにした
Flashメッセージや登録フォームまわりでStimulus を使って動きをつけてみた
このように、まずチュートリアルを写経してから自分で書くという2ステップで、Hotwireをキャッチアップすることができました。
感動した点
Turbo Streams(WebSocket)
WebSocket を利用する Turbo Streams を使うことで、リアルタイム通信機能が手軽に実装できることに感動しました。
以前、ActionCable を使ったことがあるのですが、そのときは多くの JavaScript を書く必要がありました。それが、Turbo Streams(WebSocket) を使うと、JavaScript を全く書かずにリアルタイム通信機能が実現できたのです。このコード記述量の少なさに感動しました!
Stimulus
Stimulus で感動したのは、view ファイルを見るだけで JavaScript がどんな処理をやっているのかをイメージでき、どのファイルを見ればよいのかが判断できるようになった点です。
素の JavaScript を使う場合、Rails の view ファイル上には、DOMとイベントハンドラーの関わりを示すコードが現れません。そのため、JavaScript でどの DOM要素がどのファイルでどう処理されているかをぱっと掴むことはできません。
しかし、Stimulus を使うと、viewファイルを見ただけで、DOM要素とJavaScript の関わりをイメージすることができます。Stimulusの公式ハンドブック で紹介されている以下のサンプルコードを使って、具体的に見てみましょう。
<div data-controller="hello">
<input data-hello-target="name" type="text">
<button data-action="click->hello#greet">
Greet
</button>
<span data-hello-target="output">
</span>
</div>
上記コードからは、具体的に、次のようなことを読み取ることができます。
対応する JavaScript が HelloController (hello_controller.js) であること
HelloController が、input 要素、span 要素をそれぞれ name、output という名前で参照していること
ボタンがクリックされたら、HelloController の greet() が呼ばれる
このように、view ファイルを見ただけで、ある程度 JavaScript の処理がイメージできるのは JavaScript のファイル検索の手間が減って楽だと感じました。
理解に時間がかかったところ
チュートリアルを写経している時点では理解した気になっていたものの、「自分で書く段階」になって「実は理解できていなかった」部分があったことに気づきました。後から読み直すとチュートリアルにはしっかり書いてあったのですが、私が見落としていたために理解に時間がかかってしまったようです。
この点も、参考になるかもしれないので、ここで紹介したいと思います。
turbo_stream.replace の省略記法
Rails では、Turbo Streams のレスポンスを作る際に、非常に簡略な記法で書くことができます。たとえば、「支払い情報」の更新時、更新後の支払い情報をページ上に反映するために、app/views/payments/update.turbo_stream.erb では次のように記述することになります。
<%= turbo_stream.replace @payment %>
自分のアプリで実際にコードを書いてみようとしたときに、写経時の記憶をもとにこのコードを書こうとしたのですが、実は意味がよく分かっていない、ということに気づきました。
種明かしをしてしまうと、上記のコードは payment というパーシャルテンプレートに更新された支払い情報を流し込んだ結果得られる HTML フラグメント(部分HTML)を送り出し、画面内に反映させる処理を行います。
省略記法を使わずに記述すると、次のようになります。
<%= turbo_stream.replace dom_id(@payment) do %>
<%= render partial: "payments/payment",
locals: { payment: @payment } %>
<% end %>
つまり、次のような動作をするということです。
@payment から dom_id を取得して、その dom_id と一致する要素を payments/payment のパーシャルと置換します。
このとき、payments/payment のパーシャル内で使われている payment という変数には @payment を代入します。
このように、trubo_stream.replace の実際の処理は、それなりに複雑なのですが、省略記法では引数に @payment を渡すだけで暗黙的に処理してくれるため、この記法で何をやっているのかが、なかなか腑に落ちませんでした。
私の場合、先程挙げた「省略しない書き方」を見てはじめて、見慣れた Rails のレンダリングの記法と似ていることに気づき、理解を進めることができました。
そもそも、Rails では、以下のような省略記法でパーシャルをレンダリングすることができます。
render @payment
この書き方、 turbo_stream.replace の省略記法に似ている・・・!
それまで、Hotwire はこれまでの Rails と書き方が全く違うと感じていました。しかし、従来のRailsとHotwireの記法の共通点に気づいてからは、点と点が繋がり、既存の Rails と同じように書けると理解することができました。
まとめ
以上のように、本記事では、私がどのようにHotwireをキャッチアップしたかをご紹介しました。また、Hotwireに特に感動した点や、キャッチアップの中で理解に時間がかかった点にも触れました。
キャッチアップ前までは、HotwireはRailsとは別物という感覚が強かったのですが、自分で書いて理解が深まるにつれ、既存の Rails と同じようにコードが書けて、大変使いやすいと感じています。
ご興味のある方は、本記事を参考にしていただいて、ぜひチュートリアルや自作アプリにて、Hotwireを試してみていただければと思います。
Hotwire を活用した開発に興味のあるお客様はこちらへ
https://everyleaf.com/contact-about-dev
株式会社万葉ではエンジニアの採用を行っています!
https://everyleaf.com/we-are-hiring