$30 off During Our Annual Pro Sale. View Details »

Hotwire を使って管理画面を簡単にプチSPA化する - Kaigi on Rails 2023

Hotwire を使って管理画面を簡単にプチSPA化する - Kaigi on Rails 2023

Takaharu Yamamoto

October 29, 2023
Tweet

Other Decks in Programming

Transcript

  1. Hotwire を使って
    管理画⾯を簡単にプチSPA化する
    Takaharu Yamamoto
    Kaigi on Rails 2023

    View Slide

  2. ⾃⼰紹介
    ● ⼭本孝春
    ● GitHub: yamataka22
    ● 個⼈事業主
    ● 中⼩規模システムの受託開発をしてます
    ● Railsで⼀気通貫した開発が好き

    View Slide

  3. Hotwire
    使ってますか?

    View Slide

  4. Hotwire
    使ってますか?
    情報が少ない 実績が少ない
    とりあえず無効化

    View Slide

  5. Hotwire
    使ってますか?
    情報が少ない 実績が少ない
    とりあえず無効化
    Turbolinksの⼆の舞に...?!

    View Slide

  6. 本⽇のテーマ
    Hotwireを使って管理画⾯をモーダル化する
    →この説明を通じて、Hotwireの敷居を下げたい

    View Slide

  7. ● 話すこと
    ○ HotwireでModalを扱う⽅法を、コードを例⽰しながら実践
    レベルで説明します
    ● 話さないこと
    ○ 時間の都合上、Hotwireの⼊⾨的な内容(TurboFrameとは
    何か?など)は割愛します
    今⽇の内容

    View Slide

  8. 管理画⾯にモーダルを
    使うメリットは?
    そもそも

    View Slide

  9. よくある画⾯遷移
    ⼀覧で検索をして、⾏を選択

    View Slide

  10. よくある画⾯遷移
    詳細画⾯に遷移する

    View Slide

  11. よくある画⾯遷移
    そこから⼀覧に戻ると
    indexのPath

    View Slide

  12. よくある画⾯遷移
    検索状態がリセットされてしまう

    View Slide

  13. よくある対策
    ● ブラウザの別タブで表⽰
    ○ assetsを含めた画⾯全体をリロードするので重い
    ○ 気づいたらブラウザがタブだらけ
    ● 戻るボタンに検索条件のパラメータを保持
    ○ 戻るだけなのに再度検索が⾛る
    ○ スクロール位置などは保持されない

    View Slide

  14. ⼀覧からの遷移をモーダルで開けば

    View Slide

  15. ⼀覧の状態を維持できる

    View Slide

  16. モーダル表⽰のメリット
    ● 画⾯の状態を維持しながら操作を進められる
    ● モーダル内だけ描画するので、挙動が軽い
    ● ユーザーはその画⾯に留まれる安⼼感がある

    View Slide

  17. ただし管理画⾯なので
    ● 開発にそこまでコストをかけたくない
    ● サーバーサイド側のエンジニアだけで
    UIも含めて実装することが多い

    View Slide

  18. ただし管理画⾯なので
    ● 開発にそこまでコストをかけたくない
    ● サーバーサイド側のエンジニアだけで
    UIも含めて実装することが多い
    モーダルのために作り込むことは避けたい

    View Slide

  19. そこで Hotwire

    View Slide

  20. Hotwireなら
    ● ほとんどJavaScriptを書くことなく
    ● ⼀般的な画⾯遷移版に少し⼿を⼊れるだけで
    ● 簡単にモーダル化できる

    View Slide

  21. コードの説明の前に
    ● モーダルの描画にはBootstrapを利⽤します
    ○ Bootstrap以外でも、JavaScriptを使ってモーダル表⽰の制御ができれ
    ば、他のツールでも代替可能です
    ● 時間の都合上、細かな部分は説明を省略します
    ○ 本⽇説明するコードはGitHubで公開してます
    github.com/yamataka22/kaigionrails2023-admin-modal

    View Slide

  22. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  23. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  24. モーダル表⽰のポイント
    ● TurboFrameを使って、モーダル部分のHTMLの破⽚を⽣
    成する
    ● その破⽚がブラウザに読み込まれたタイミングで、
    Stimulusのインスタンスを⽣成し、connect()を経由して
    モーダルを開く

    View Slide

  25. app/views/application/_remote_modal.html.erb
    Modal表⽰のerb (TurboFrame)

    View Slide

  26. app/views/application/_remote_modal.html.erb
    中⾝はBootstrapの⼀般的な
    Modal Component
    turbo_frame_tag で囲む
    Modal表⽰のerb (TurboFrame)

    View Slide

  27. app/views/application/_remote_modal.html.erb
    ポイントはここ!
    破⽚の中から、Stimulusの
    controllerを指定する
    この破⽚がブラウザに組み込まれたタイミングで
    該当Stimulusのインスタンスが⽣成される
    →TurboFrameとStimulusを連携して、動きをつけられる
    Modal表⽰のerb (TurboFrame)

    View Slide

  28. app/javascript/controllers/remote_modal_controller.js
    Modal表⽰のStimulus
    ● `connect()`は、Stimulusのインス
    タンスが⽣成されたときに⾃動的に
    起動するメソッド
    ● TurboFrameで読み込んだHTMLに対
    して、Stimulusで動きをつけられる
    ● `disconnect()`もある

    View Slide

  29. これだけでモーダル表⽰できる
    🎉

    View Slide

  30. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  31. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  32. ⼀般的な画⾯遷移による更新処理
    編集フォームから更新すると

    View Slide

  33. ⼀般的な画⾯遷移による更新処理
    エラーがあれば編集画⾯にとどまり

    View Slide

  34. ⼀般的な画⾯遷移による更新処理
    更新に成功したら詳細画⾯にリダイレクトする

    View Slide

  35. ⼀般的な画⾯遷移による更新処理
    更新に成功したら詳細画⾯にリダイレクトする
    モーダルでも同等な動きを実現したい

    View Slide

  36. モーダルでの更新処理
    編集フォームから更新すると

    View Slide

  37. モーダルでの更新処理
    エラーがあればモーダル上で表示され

    View Slide

  38. モーダルでの更新処理
    更新後に詳細画⾯が表⽰される

    View Slide

  39. Controller#update
    app/controllers/products_controller.rb

    View Slide

  40. Controller#update
    ● 更新に成功しても、redirectしない
    ● update.turbo_stream.erbがレンダリ
    ング対象
    ● 本来redirectするパス (product_path)
    を@turbo_pathにセット
    →これは後述にて説明
    app/controllers/products_controller.rb

    View Slide

  41. Controller#update
    invalidの場合は :edit を再度レンダリン
    グする
    →これは通常の画⾯遷移時と同様
    app/controllers/products_controller.rb

    View Slide

  42. Turbo Stream
    app/views/products/update.turbo_stream.erb

    View Slide

  43. Turbo Stream
    remote_modal の部分を @product で `replace` する
    (モーダルの内容が詳細画⾯に変わる)
    app/views/products/update.turbo_stream.erb

    View Slide

  44. Turbo Stream
    app/views/products/update.turbo_stream.erb
    ⼀覧(index) に表⽰されているレコードの内容も
    最新化する

    View Slide

  45. 以上で登録後の遷移ができる

    View Slide

  46. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  47. やること
    1. TurboFrame + Stimulus でモーダルを開く
    2. TurboStream で登録後の描画を切り替える
    3. ブラウザのURLを追随させる

    View Slide

  48. 管理画⾯の運⽤でよくあるシーン
    URLを使ってやり取りすることが多々ある
    例えばSlackで...

    View Slide

  49. 管理画⾯の運⽤でよくあるシーン
    URLを使ってやり取りすることが多々ある
    例えばSlackで...
    こんな感じで該当ページのURLを使って
    コミュニケーションしたい

    View Slide

  50. 単にModal化しただけでは
    ブラウザのURLが追随しない
    →URLを使った運⽤ができない
    管理画⾯の実運⽤も考慮して
    対処したい

    View Slide

  51. 2つの対策を提案
    a) モーダル起動の link_to に `turbo_action: :advance` を指定
    b) JavaScriptの History API を使って制御する

    View Slide

  52. 2つの対策を提案
    a) モーダル起動の link_to に `turbo_action: :advance` を指定
    ∙ Railsの仕組みでできるのでシンプル
    ∙ Modalを閉じたときや、更新後の表⽰切り替え時に追随しない
    b) JavaScriptの History API を使って制御する
    ∙ URLのために仕組みを実装する必要
    ∙ Modalを閉じたとき、更新後の表⽰切り替えも追随できる

    View Slide

  53. 2つの対策を提案
    a) モーダル起動の link_to に `turbo_action: :advance` を指定
    ∙ Railsの仕組みでできるのでシンプル
    ∙ Modalを閉じたときや、更新後の表⽰切り替え時に追随しない
    b) JavaScriptの History API を使って制御する
    ∙ URLのために仕組みを実装する必要
    ∙ Modalを閉じたとき、更新後の表⽰切り替えも追随できる
    今回はこちらの内容を説明

    View Slide

  54. 以下2つのURLを使う
    ● Modalを表⽰したときのURL
    ○ TurboFrameによるGETリクエスト or リダイレクトのURL
    ○ Modalを開く際に、HistoryAPIにセットする
    ● Modalを閉じたときのURL
    ○ Modalを開く直前のURLを location.href から取得しておく
    ○ Modalのhideイベントをフックして、このURLに戻す

    View Slide

  55. app/controllers/application_controller.rb
    ApplicationControllerの
    before_action で、turboでリクエスト
    されたURLを @turbo_path へセットし
    ておく
    Modal起動時のURL
    GETリクエストでModalを起動する

    View Slide

  56. app/controllers/products_controller.rb
    例えば #update に成功すると、通常の画⾯遷移版
    では show_path へリダイレクトする。
    そのpathを @turbo_path としてセットしておく。
    Modal起動時のURL
    Modalにリダイレクトの動きをさせたい場合

    View Slide

  57. app/views/application/_remote_modal.html.erb
    @turbo_path をModalに付与しておき、Stimulusを介
    してHistoyAPIにセットする
    前項で説明した turbo_frame でModal表示をするerb

    View Slide

  58. app/javascript/controllers/remote_modal_controller.js
    前述で説明した、Stimulusのconnect()を使って
    Modalを開くロジック部分
    Modalを起動するStimulus

    View Slide

  59. Modalを開く前に、URLの仕組みを
    ⼊れる
    app/javascript/controllers/remote_modal_controller.js
    Modalを起動するStimulus

    View Slide

  60. app/javascript/controllers/remote_modal_controller.js
    Modalを起動するStimulus
    前述の `turboPath` を HistoryAPIにセットするこ
    とで、Modal起動時にURLを追随させる

    View Slide

  61. 現在のパス=Modalを開く直前のパ
    ス (`location.href`) を、Modal#hide
    イベントをフックしてセットする
    app/javascript/controllers/remote_modal_controller.js
    Modalを起動するStimulus

    View Slide

  62. 以上でブラウザ上のURLが追随します

    View Slide

  63. ちなみに、この状態で
    URLを直接指定したリクエストをすると...

    View Slide

  64. 特に何も仕組みを設けなくても表⽰できる

    View Slide

  65. コード補足
    a) 登録フォームのModalは、背景クリックでも閉じないように
    ● ⼊⼒途中にうっかりModalが閉じることを防ぐ
    ● 詳細ページなら背景クリックで閉じたほうが便利
    b) Flashによるメッセージ表⽰
    ● Turboだと少し仕組みを設ける必要
    サンプルのGitHubリポジトリで実装しています
    github.com/yamataka22/kaigionrails2023-admin-modal

    View Slide

  66. まとめ
    ● Hotwireを使って、管理画⾯をModalでプチSPA化するポイントを説明
    しました
    ○ TurboFrameとStimulus (connect()) を連携させて、HTMLの破⽚に動き
    をつける
    ○ TurboStreamで、Modal上の描画を切り替える(リダイレクトのイメー
    ジ)
    ● 今回説明した内容は、管理画⾯はもちろん、⼀般的なフロント向け
    ページでも応⽤可能です

    View Slide

  67. ご清聴ありがとうございました
    ※ご不明な点などあれば、お気軽にご連絡ください
    github.com/yamataka22

    View Slide