Action Cableを使用したリアルタイムチャットで投稿者の名前を表示させる方法についてのまとめ。
メッセージの投稿機能はできたが、誰が投稿したものか分からないため投稿者の名前を表示させたい人のために書きました。
Action Cable の大まかな仕組みの説明
Action Cableは、通常のRailsのアプリケーションと同様の記述で、即時更新機能を実装できるフレームワークです。
実装内容
・メッセージの保存や送信に必要なRubyのコーディング
・保存したメッセージを即時に表示させるJavaScriptのコーディング
Channel(チャネル)とは?
即時更新機能を実現するサーバー側の仕組みのこと。
メッセージを即座に表示させるために、データの経路を設定したり、送られてきたデータをクライアントの画面上に表示させるJavaScriptを記述したりします。
これらの役割をChannel(チャネル)が担っています。
チャネルを作成すると作られる2つのファイル
1.message_channel.rb と 2.message_channel.js
1.message_channel.rb はクライアントとサーバーを結びつけるためのファイル
stream_fromメソッドを使用して結びつける。MVCでいうところのルーティングの機能。
stream_fromメソッドで関連付けられるデータの経路(図:ピンク色の←の部分)のことを、broadcast (ブロードキャスト)と呼びます。
メッセージの保存が成功したときに、broadcastを介してメッセージが送信されるように◯◯◯_controller.rbに記述します。
2.message_channel.js はサーバーから送られてきたデータをクライアントの画面に描画するためのファイル
投稿内容と投稿したユーザーを紐付ける
message_channel.rbに stream_from "message_channel" でクライアントとサーバーを結びつけていること前提。
class MessageChannel < ApplicationCable::Channel
def subscribed
stream_from "message_channel"
end
message_params にログイン中のユーザーidをマージさせる。
current_userを@userというインスタンス変数に代入してbroadcastを介して、user: @userのデータが送信されるようにする。
controller.rbに記述
def create
@message = Message.new(message_params)
@user = current_user
if @message.save
ActionCable.server.broadcast 'message_channel', content: @message, user: @user
end
end
private
def message_params
params.require(:message).permit(:text).merge(user_id: current_user.id)
end
投稿内容と投稿者の名前、投稿日時を表示させる
message_channel.js にクライアントの画面上に表示させる記述を行う。
受け取った情報は、receivedの引数dataに入ります。
表示に関してはhtmlの部分の記述。
* 私は見やすいように名前はspan要素を使って括弧で囲んで、p要素でメッセージ名前と投稿日時の下に来るように段落を作っています。
received(data) {
const html = `<p><span>【</span>${data.user.name}<span>】</span>${data.content.updated_at}</p>
<p>${data.content.text}</p>`;
const messages = document.getElementById('messages');
const newMessage = document.getElementById('message_text');
messages.insertAdjacentHTML('afterbegin', html);
newMessage.value='';
}
});
まとめ
今回Action Cableを初めて使って、リアルタイムチャットアプリを作成しました。
個人的にはコントローラーの記述が難しかったですが、一度使い方や流れを理解できると名前や日時だけでなくいろいろなデータを結び付けて表示させることができると思いました。
リロードすると表示の形が変わってしまう点の改善や無限スクロール機能がまだできず勉強中です。