これまでの実装で、LiveViewを使って自分の発言を表示することができるようになりました。
ただし、その掲示板を見ている全員にもリアルタイムに状況を更新するには、もうひと段階が必要になります。
今回は、その部分を実装します。
本記事でリアルタイム更新が可能になります。
本テーマは7記事構成になっています。
7記事それぞれで取り扱う内容は以下です。
本テーマは以下の方針で記述します。
完成版の画面イメージは以下のようになっています。
現状では、投稿をしたら自分のブラウザはリアルタイムに更新がされるようになるものの、同じチャットボードを見ている他のユーザーには状態が反映されません。
状態が反映されるようにするためには、Phoenix.PubSubを利用します。
行うことは以下の3点です。
トピックIDを board:<<ボードID>> という形式にします。
例えばID=1のチャットボードは "board:1" となります。
そのトピックIDに対してマウント時に購読処理を行います。
ハイライト箇所が、今回追加したところです。
# /lib/lv_chat_web/views/board_live_view.ex
defp topicId(board_id) do "board:#{board_id}"end
def mount(session = %{current_user: _user, board: board}, socket) do
assigns =
Map.merge(
session,
%{
comments: board |> Meeting.list_comments,
comment: LvChat.Meeting.change_comment
}
)
session.board.id |> topicId |> LvChatWeb.Endpoint.subscribe()
{:ok, assign(socket, assigns)}
end
LiveViewにてコメントが追加されたときに、broadcastを行う処理を追加します。
ハイライト箇所が、今回追加したところです。
# /lib/lv_chat_web/views/board_live_view.ex
def handle_event(
"add_comment",
%{"comment" => cmnt},
socket = %{assigns: %{board: board, current_user: user}}
) do
case Meeting.comment_to_board(user, board.id, cmnt) do
{:ok, _comment} ->
comments = board |> Meeting.list_comments
LvChatWeb.Endpoint.broadcast_from(self(), board.id |> topicId, "broadcast_comment", %{ comments: comments })
{:noreply, assign(socket, comment: LvChat.Meeting.change_comment, comments: comments)}
{:error, _changeset} ->
{:noreply, socket}
end
end
broadcast_commentに対応します。
stateに全発言が含まれていますので、これを更新するだけです。
def handle_info(%{event: "broadcast_comment", payload: state}, socket) do
{:noreply, assign(socket, state)}
end
これで、チャットとしての機能は完成しました。
リアルタイムに情報が更新される部分の実装は、割と簡単に終わりました。