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