Hotwire を使って管理画面を簡単にプチSPA化する - Kaigi on Rails 2023
by
Takaharu Yamamoto
×
Copy
Open
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
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