https://kaigionrails.org/2023/talks/yamataka/
Hotwire を使って管理画⾯を簡単にプチSPA化するTakaharu YamamotoKaigi on Rails 2023
View Slide
⾃⼰紹介● ⼭本孝春● GitHub: yamataka22● 個⼈事業主● 中⼩規模システムの受託開発をしてます● Railsで⼀気通貫した開発が好き
Hotwire使ってますか?
Hotwire使ってますか?情報が少ない 実績が少ないとりあえず無効化
Hotwire使ってますか?情報が少ない 実績が少ないとりあえず無効化Turbolinksの⼆の舞に...?!
本⽇のテーマHotwireを使って管理画⾯をモーダル化する→この説明を通じて、Hotwireの敷居を下げたい
● 話すこと○ HotwireでModalを扱う⽅法を、コードを例⽰しながら実践レベルで説明します● 話さないこと○ 時間の都合上、Hotwireの⼊⾨的な内容(TurboFrameとは何か?など)は割愛します今⽇の内容
管理画⾯にモーダルを使うメリットは?そもそも
よくある画⾯遷移⼀覧で検索をして、⾏を選択
よくある画⾯遷移詳細画⾯に遷移する
よくある画⾯遷移そこから⼀覧に戻るとindexのPath
よくある画⾯遷移検索状態がリセットされてしまう
よくある対策● ブラウザの別タブで表⽰○ assetsを含めた画⾯全体をリロードするので重い○ 気づいたらブラウザがタブだらけ● 戻るボタンに検索条件のパラメータを保持○ 戻るだけなのに再度検索が⾛る○ スクロール位置などは保持されない
⼀覧からの遷移をモーダルで開けば
⼀覧の状態を維持できる
モーダル表⽰のメリット● 画⾯の状態を維持しながら操作を進められる● モーダル内だけ描画するので、挙動が軽い● ユーザーはその画⾯に留まれる安⼼感がある
ただし管理画⾯なので● 開発にそこまでコストをかけたくない● サーバーサイド側のエンジニアだけでUIも含めて実装することが多い
ただし管理画⾯なので● 開発にそこまでコストをかけたくない● サーバーサイド側のエンジニアだけでUIも含めて実装することが多いモーダルのために作り込むことは避けたい
そこで Hotwire
Hotwireなら● ほとんどJavaScriptを書くことなく● ⼀般的な画⾯遷移版に少し⼿を⼊れるだけで● 簡単にモーダル化できる
コードの説明の前に● モーダルの描画にはBootstrapを利⽤します○ Bootstrap以外でも、JavaScriptを使ってモーダル表⽰の制御ができれば、他のツールでも代替可能です● 時間の都合上、細かな部分は説明を省略します○ 本⽇説明するコードはGitHubで公開してますgithub.com/yamataka22/kaigionrails2023-admin-modal
やること1. TurboFrame + Stimulus でモーダルを開く2. TurboStream で登録後の描画を切り替える3. ブラウザのURLを追随させる
モーダル表⽰のポイント● TurboFrameを使って、モーダル部分のHTMLの破⽚を⽣成する● その破⽚がブラウザに読み込まれたタイミングで、Stimulusのインスタンスを⽣成し、connect()を経由してモーダルを開く
app/views/application/_remote_modal.html.erbModal表⽰のerb (TurboFrame)
app/views/application/_remote_modal.html.erb中⾝はBootstrapの⼀般的なModal Componentturbo_frame_tag で囲むModal表⽰のerb (TurboFrame)
app/views/application/_remote_modal.html.erbポイントはここ!破⽚の中から、Stimulusのcontrollerを指定するこの破⽚がブラウザに組み込まれたタイミングで該当Stimulusのインスタンスが⽣成される→TurboFrameとStimulusを連携して、動きをつけられるModal表⽰のerb (TurboFrame)
app/javascript/controllers/remote_modal_controller.jsModal表⽰のStimulus● `connect()`は、Stimulusのインスタンスが⽣成されたときに⾃動的に起動するメソッド● TurboFrameで読み込んだHTMLに対して、Stimulusで動きをつけられる● `disconnect()`もある
これだけでモーダル表⽰できる🎉
⼀般的な画⾯遷移による更新処理編集フォームから更新すると
⼀般的な画⾯遷移による更新処理エラーがあれば編集画⾯にとどまり
⼀般的な画⾯遷移による更新処理更新に成功したら詳細画⾯にリダイレクトする
⼀般的な画⾯遷移による更新処理更新に成功したら詳細画⾯にリダイレクトするモーダルでも同等な動きを実現したい
モーダルでの更新処理編集フォームから更新すると
モーダルでの更新処理エラーがあればモーダル上で表示され
モーダルでの更新処理更新後に詳細画⾯が表⽰される
Controller#updateapp/controllers/products_controller.rb
Controller#update● 更新に成功しても、redirectしない● update.turbo_stream.erbがレンダリング対象● 本来redirectするパス (product_path)を@turbo_pathにセット→これは後述にて説明app/controllers/products_controller.rb
Controller#updateinvalidの場合は :edit を再度レンダリングする→これは通常の画⾯遷移時と同様app/controllers/products_controller.rb
Turbo Streamapp/views/products/update.turbo_stream.erb
Turbo Streamremote_modal の部分を @product で `replace` する(モーダルの内容が詳細画⾯に変わる)app/views/products/update.turbo_stream.erb
Turbo Streamapp/views/products/update.turbo_stream.erb⼀覧(index) に表⽰されているレコードの内容も最新化する
以上で登録後の遷移ができる
管理画⾯の運⽤でよくあるシーンURLを使ってやり取りすることが多々ある例えばSlackで...
管理画⾯の運⽤でよくあるシーンURLを使ってやり取りすることが多々ある例えばSlackで...こんな感じで該当ページのURLを使ってコミュニケーションしたい
単にModal化しただけではブラウザのURLが追随しない→URLを使った運⽤ができない管理画⾯の実運⽤も考慮して対処したい
2つの対策を提案a) モーダル起動の link_to に `turbo_action: :advance` を指定b) JavaScriptの History API を使って制御する
2つの対策を提案a) モーダル起動の link_to に `turbo_action: :advance` を指定∙ Railsの仕組みでできるのでシンプル∙ Modalを閉じたときや、更新後の表⽰切り替え時に追随しないb) JavaScriptの History API を使って制御する∙ URLのために仕組みを実装する必要∙ Modalを閉じたとき、更新後の表⽰切り替えも追随できる
2つの対策を提案a) モーダル起動の link_to に `turbo_action: :advance` を指定∙ Railsの仕組みでできるのでシンプル∙ Modalを閉じたときや、更新後の表⽰切り替え時に追随しないb) JavaScriptの History API を使って制御する∙ URLのために仕組みを実装する必要∙ Modalを閉じたとき、更新後の表⽰切り替えも追随できる今回はこちらの内容を説明
以下2つのURLを使う● Modalを表⽰したときのURL○ TurboFrameによるGETリクエスト or リダイレクトのURL○ Modalを開く際に、HistoryAPIにセットする● Modalを閉じたときのURL○ Modalを開く直前のURLを location.href から取得しておく○ Modalのhideイベントをフックして、このURLに戻す
app/controllers/application_controller.rbApplicationControllerのbefore_action で、turboでリクエストされたURLを @turbo_path へセットしておくModal起動時のURLGETリクエストでModalを起動する
app/controllers/products_controller.rb例えば #update に成功すると、通常の画⾯遷移版では show_path へリダイレクトする。そのpathを @turbo_path としてセットしておく。Modal起動時のURLModalにリダイレクトの動きをさせたい場合
app/views/application/_remote_modal.html.erb@turbo_path をModalに付与しておき、Stimulusを介してHistoyAPIにセットする前項で説明した turbo_frame でModal表示をするerb
app/javascript/controllers/remote_modal_controller.js前述で説明した、Stimulusのconnect()を使ってModalを開くロジック部分Modalを起動するStimulus
Modalを開く前に、URLの仕組みを⼊れるapp/javascript/controllers/remote_modal_controller.jsModalを起動するStimulus
app/javascript/controllers/remote_modal_controller.jsModalを起動するStimulus前述の `turboPath` を HistoryAPIにセットすることで、Modal起動時にURLを追随させる
現在のパス=Modalを開く直前のパス (`location.href`) を、Modal#hideイベントをフックしてセットするapp/javascript/controllers/remote_modal_controller.jsModalを起動するStimulus
以上でブラウザ上のURLが追随します
ちなみに、この状態でURLを直接指定したリクエストをすると...
特に何も仕組みを設けなくても表⽰できる
コード補足a) 登録フォームのModalは、背景クリックでも閉じないように● ⼊⼒途中にうっかりModalが閉じることを防ぐ● 詳細ページなら背景クリックで閉じたほうが便利b) Flashによるメッセージ表⽰● Turboだと少し仕組みを設ける必要サンプルのGitHubリポジトリで実装していますgithub.com/yamataka22/kaigionrails2023-admin-modal
まとめ● Hotwireを使って、管理画⾯をModalでプチSPA化するポイントを説明しました○ TurboFrameとStimulus (connect()) を連携させて、HTMLの破⽚に動きをつける○ TurboStreamで、Modal上の描画を切り替える(リダイレクトのイメージ)● 今回説明した内容は、管理画⾯はもちろん、⼀般的なフロント向けページでも応⽤可能です
ご清聴ありがとうございました※ご不明な点などあれば、お気軽にご連絡くださいgithub.com/yamataka22