皆さん、こんにちは。おっくんです。
最近は HotWire に関する記事を続けていますが、ラボ内のメンバーから前回の記事について、とある一つの意見がありました。 「Turbo Streams で変更のブロードキャストをするとき、モデルからビューに対しての更新が発信されるのは、少し気持ち悪いです。」
「なるほど、確かに!」と思いましたので、今回はコントローラーから明示的にブロードキャスト操作を呼び出してみたいと思います。
実行環境
- macOS 10.15.17
- Redis 5.0.7
- Ruby 3.0.0
作るもの
Hotwire に トースト通知 機能を作るで定義したアプリケーションの要件は以下の通りでした。
- 簡単な 1 部屋 1 画面だけのチャットアプリ
- 書き込みを検索できる機能
- 書き込みの検索結果を表示している間に新しい投稿があった時は、新着通知を表示する機能
- 投稿者の投稿の保存結果をトーストで通知する
こちらについて、モデルからビューに直接ブロードキャストさせず、コントローラから明示的にブロードキャストをトリガーさせます。
実装
サンプルコードでのブロードキャストの実装例を手始めに、前回作成したアプリケーション、今回のコントローラから明示的にブロードキャストをトリガーさせるパターンを順に紹介します。
サンプルコード
hotwired / hotwire-rails-demo-chat/app/models/room.rb を見ると、次のようにモデルが実装されています。
[app/models/message.rb]
class Room < ApplicationRecord has_many :messages, dependent: :destroy broadcasts end
broadcasts
により、Turbo Streams
でのブロードキャストを設定しています。
前回作成したアプリケーション
前回作成したアプリケーションでは、チャンネルや明示的に使用するテンプレートの指定し ActiveRecord のコールバックで呼び出しました。
[app/models/post.rb]
class Post < ApplicationRecord validates :comment, presence: true after_create_commit do broadcast_prepend_to "post-list", target: "post-list-el", partial: "posts/post" broadcast_replace_to "post-info", target: "post-info-el", partial: "posts/info" end end
この方法で実装すると、詳細に設定できる上に複数のチャンネルへのブロードキャストをすることができます。 また、create 時だけブロードキャストするなどの操作が容易なので、個人的にはこちらの記述方法の方が好みです。
コントローラから明示的にブロードキャストとトリガーさせるパターン
ここからが今回の本題です。
app/models/post.rb
を以下のように修正し、新たなメソッドでブロードキャストを呼び出します。
[app/models/post.rb]
class Post < ApplicationRecord validates :comment, presence: true def broadcast broadcast_prepend_to "post-list", target: "post-list-el", partial: "posts/post" broadcast_replace_to "post-info", target: "post-info-el", partial: "posts/info" end end
このようにメソッドで定義すると、コントローラーで以下のように呼び出すことができます。
[app/controllers/posts_controller.rb]
class PostsController < ApplicationController def index # 省略 end def create @post = Post.new(post_params) if @post.save @success = "success" # ブロードキャスト操作をコントローラーで呼び出す @post.broadcast end return respond_to do |format| format.turbo_stream do render turbo_stream: turbo_stream.replace("post-toast-el", partial: "posts/save_result", locals: { success: @success }) end end end # 省略 end
このようにすることで、ブロードキャストのきっかけを実装者がよりコントロールすることができます。 ActiveRecord のコールバックを呼び出さないようにデータを更新する手段が無いわけではありませんが、やや不便な印象があります。
今回のラボ内での意見を受けて、Turbo Streams のブロードキャスト機能をモデルの更新から切り出してみました。 実際やってみて、「一般ユーザーの更新は通知するが管理者ユーザーの更新は通知しない」や、「他のアクセスしている人向けのブロードキャストはするが、投稿者自体はリダイレクトさせる」など柔軟なコントロールがよりしやすいのではないかな?と感じました。
P.S.
直近のイベント情報
■5月21日(金)19:30~ とらのあなラボエンジニア座談会Vol.8【なぜとらラボエンジニアはラジオを始めたのか】
を開催します!興味のある方はぜひご参加ください!
■5月28日(金)19:30~ 【オンライン】オタクが最新技術を追うLTイベント#24【初心者歓迎】【テーマフリー】 を開催します!こちらは発表者も募集中ですので、LT初心者という方でもぜひご応募ください!
採用情報
■募集職種
yumenosora.co.jp
カジュアル面談も随時開催中です
■お申し込みはこちら!
yumenosora.connpass.com
■ToraLab.fmスタートしました!
メンバーによるPodcastを配信中!
是非スキマ時間に聞いて頂けると嬉しいです。
anchor.fm
■Twitterもフォローしてくださいね!
ツイッターでも随時情報発信をしています
twitter.com