カテゴリー
サインイン 新規登録

間違いや改善の指摘

内容の技術的な誤り・誤字脱字やミスのご報告・解説やトピックの追記/改善のご要望は教材をさらに良くしていく上でとても貴重なご意見になります。

少しでも気になった点があれば、ご遠慮なく投稿いただけると幸いです🙏

実際には誤りではなく勘違いであっても、ご報告いただけることで教材のブラッシュアップにつながります。

質問ポリシー①

教材受講者みなさんのスムーズな問題解決のために、心がけていただきたいことがあります。

教材の内容に関する質問を投稿しましょう

教材の内容に関係のない質問や教材とは異なる環境・バージョンで進めている場合のエラーなど、教材に関係しない質問は推奨していないため回答できない場合がございます。

その場合、teratailなどの外部サイトを利用して質問することをおすすめします。教材の誤字脱字や追記・改善の要望は「文章の間違いや改善点の指摘」からお願いします。

12-6

Action Cable を使ったチャット機能の実装

本パートでは、リアルタイムでメッセージを送るために Action Cable を使った実装をおこないます。

本パートのゴール

本パートでは、チャットルームページのフォーム内でテキストを入力しEnterを押すと、入力した内容をアラートで表示するところまで実装します。

image

ゴールまでの流れ

  1. Action Cable とは
  2. ChatRoomチャネルの作成
  3. chat_room_channel.rb の実装
  4. chat_room_channel.js の実装

では進めていきましょう。

1. Action Cable とは

Action Cable とは、WebSocketとRailsのその他の部分をシームレスに統合するためのものです。Action Cable が Rails5 から導入されたことで、Rails アプリケーションの効率の良さとスケーラビリティを損なわずに、通常の Rails アプリケーションと同じスタイル・方法でリアルタイム機能をRubyで記述できます。

参考: Action Cable の概要

WebSocket とは、ユーザーのブラウザとサーバー間を常時接続状態にして双方向通信ができる技術です。

参考: WebSocket

2. ChatRoomチャネルの作成

それでは、Action Cableの設定をおこなっていきます。

Action Cable では、チャネル(Channel) というものを作成します。チャネルには論理的な処理を記載します。MVCのコントローラーが果たす役割と似ています。

それでは、以下のコマンドを実行して、ChatRoomチャネルを作成しましょう。

console
Copied!
rails g channel chat_room speak

実行結果は以下になります。

console
Copied!
rails g channel chat_room speak Running via Spring preloader in process 28144 invoke test_unit create test/channels/chat_room_channel_test.rb create app/channels/chat_room_channel.rb identical app/javascript/channels/index.js identical app/javascript/channels/consumer.js create app/javascript/channels/chat_room_channel.js

作成された、chat_room_channel.rbchat_room_channel.jsの中身は以下のようになっています。

app/channels/chat_room_channel.rb
123456789101112
Copied!
class ChatRoomChannel < ApplicationCable::Channel def subscribed # stream_from "some_channel" end def unsubscribed # Any cleanup needed when channel is unsubscribed end def speak end end
app/javascript/channels/chat_room_channel.js
12345678910111213141516171819
Copied!
import consumer from "./consumer" consumer.subscriptions.create("ChatRoomChannel", { connected() { // Called when the subscription is ready for use on the server }, disconnected() { // Called when the subscription has been terminated by the server }, received(data) { // Called when there's incoming data on the websocket for this channel }, speak: function() { return this.perform('speak'); } });

3. chat_room_channel.rb の実装

次に、サーバーサイドの処理をするapp/channels/chat_room_channel.rbの実装をします。

app/channels/chat_room_channel.rb を以下のように編集してください。

app/channels/chat_room_channel.rb
12345678910111213141516
Copied!
class ChatRoomChannel < ApplicationCable::Channel def subscribed # この行を編集する stream_from "chat_room_channel" end def unsubscribed # Any cleanup needed when channel is unsubscribed end # ==========ここから編集する========== def speak(data) ActionCable.server.broadcast 'chat_room_channel', chat_message: data['chat_message'] end # ==========ここまで編集する========== end
rb
123
Copied!
def subscribed stream_from "chat_room_channel" end

subscribedでどのchannel(今回はchat_room_channel)を購読するか指定します。このコードで、chat_room_channel.rbchat_room_channel.jsでデータ送受信できます。

rb
123
Copied!
def speak(data) ActionCable.server.broadcast 'chat_room_channel', chat_message: data['chat_message'] end

上記のコードで、chat_room_channel.jsで実行されたspeakアクションのchat_messageを受け取り、chat_room_channel.jsreceivedメソッドにdataを送信します。

4. chat_room_channel.js の実装

次に、クライアントサイドの処理をするapp/javascripts/channels/room_channel.jsを実装します。

最初は、フォームに文字を入力してエンターを押したら、アラートを表示するところまで実装します。

app/javascripts/channels/room_channel.js
1234567891011121314151617181920212223242526272829303132333435
Copied!
import consumer from "./consumer" // この行を編集する const appChatRoom = consumer.subscriptions.create("ChatRoomChannel", { connected() { // Called when the subscription is ready for use on the server }, disconnected() { // Called when the subscription has been terminated by the server }, received(data) { // この行を編集する return alert(data['chat_message']); }, // ==========ここから編集する========== speak: function(chat_message) { return this.perform('speak', { chat_message: chat_message }); } // ==========ここまで編集する========== }); // ==========ここから追加する========== if(/chat_rooms/.test(location.pathname)) { $(document).on("keydown", ".chat-room__message-form_textarea", function(e) { if (e.key === "Enter") { appChatRoom.speak(e.target.value); e.target.value = ''; e.preventDefault(); } }) } // ==========ここまで追加する==========
js
1
Copied!
if(/chat_rooms/.test(location.pathname)) {

上記のコードでチャットルームページかどうかを確かめています。チャットルームページだけで上記の処理をしたいためです。

location.pathname で現在のページURLのパスを参照します。http://localhost:3000/chat_rooms/1 にアクセスしたら、/chat_rooms/1を取得します。

.test()メソッドは、正規表現で指定された文字列の一致を調べるための検索を実行します。正であればtrueを返します。

参考: MDN web docs - RegExp.prototype.test()

js
12
Copied!
$(document).on("keydown", ".chat-room__message-form_textarea", function(e) { if (e.key === "Enter") {

上記のコードで、フォーム内でEnterキーを押したときに処理を実行します。

js
1
Copied!
appChatRoom.speak(e.target.value);

上記のコードで、speakアクションを発火させています。

js
123
Copied!
speak: function(chat_message) { return this.perform('speak', { chat_message: chat_message }); }

上記のコードで、chat_room_channel.rbのspeakアクションにchat_messageを送っています。

js
123
Copied!
received(data) { return alert(data['chat_message']); },

上記のコードで、chat_room_channel.rbから送られてきたdataを受け取り、アラートを表示します。

それでは、動作確認をしてみましょう。

チャットルームページにアクセスして、フォームにテキストを入力し、Enterキーを押してください。

image

上記の動画のように入力したテキストがアラートに表示されればうまく動作しています。

アラート表示までの流れ

ここまでのアラート表示までの流れは以下になります。

  1. チャットルームページのフォーム内でEnterキーを押す
  2. chat_room_channel.js の appChatRoom の speak アクションが発火
  3. 入力したテキスト(chat_message)を chat_room_channel.rb の speak アクションに送る
  4. chat_room_channel.rb の speak アクションでは、送られたchat_messageを受け取り、chat_room_channel.js の received に data を送る
  5. データを受け取ったreceivedでは、受け取ったデータをアラートで表示

以上で本パートは終了です。

次のパートでも引き続き Action Cable の実装を進めていきます。

お疲れさまでした。