はじめに
本記事は錆びかけたRailsの知識を頑張ってアップデートするアドベントカレンダー22日目です。
今回は、リアルタイムメッセージ送信機能の実装を考えます。
この時、UIはLINEのように自分のメッセージと他の人のメッセージとの区別がつくような形を想定します。
画像引用:https://linecorp.com/ja/pr/news/ja/2020/3520
課題
こちらは参考にした記事に詳しいのですが、turbo streamを利用したfetchで部分テンプレート部分を更新する場合、current_user
を利用することができません。
解決方法
更新したメッセージがcurrent_user
のものかどうかは、Stimulusを使って別途伝える必要があります。
その際、以下のようにログインしているユーザーのidをbodyタグに仕込み、Stimulusに渡すようにします。
<!-- app/views/layouts/application.html.erb -->
<body data-controller="application" data-application-user-id-value="<%= current_user.id if user_signed_in? %>">
<%= yield %>
</body>
bodyタグに仕込んだcurrent_userのidは、Stimulusのコントローラで以下のように取得できます。
// app/javascript/controllers/application_controller.js
import { Controller } from "@hotwired/stimulus"
export default class ApplicationController extends Controller {
// 共通のメソッドや値を定義
static values = { userId: Number }
}
このコントローラを継承した別のコントローラを作ると、current_userの値が共通化できてよさそうです。
// app/javascript/controllers/message_controller.js
import ApplicationController from "./application_controller"
export default class extends ApplicationController {
connect() {
if (this.userIdValue === Number(this.element.dataset.userId)) {
// 現在のユーザーによるメッセージの場合の処理
} else {
// それ以外の場合の処理
}
}
}
あとは、リアルタイム通信時にブロードキャストされる部分テンプレートをStimulusで捕捉し、接続されたタイミングで左右に出し分けるCSSを当てるようにすればよさそうですね。
<!-- app/views/messages/_message.html.erb -->
<div id="message_<%= message.id %>"
class="message <%# デフォルトは左側に表示 %>"
data-controller="message"
data-message-user-id-value="<%= message.user.id %>">
<!-- メッセージの内容 -->
</div>
終わりに
今回はRails側のコントローラ部分や、HotWireによるリアルタイム通信の部分は触れなかったので、機会があればその辺もまとめて実装方法として公開したいですね。
参考
こちらの記事を参考にさせていただきました。