こちらの記事を参考にActionCableでシンプルにSocket通信を利用してチャットができるようになるまでを実装したいと思います。
もともとあった他のアプリにもwebsocketで通信するスクリプトが入ってしまって、表示のパフォーマンスに影響があったので既存に組み込みよりも、新規にプロジェクトを作成する事をおすすめします。
対象コミットはこちら
自分用のメモでもあるのでコミット一覧もはります。
全体的な流れは、
ページを表示→ウェブソケットでJSからサーバーに接続
→ブラウザからデータを送信
→サーバー側で受け取りRedisに格納
→格納したデータをBroadcast
→サイドブラウザで受け取り表示する
1. Redisのインストールと起動
とりあえずインストールして起動しておきます。
wget http://download.redis.io/releases/redis-3.2.3.tar.gz
tar -xzvf redis-3.2.3.tar.gz
cd redis-3.2.3
make
make install
/usr/local/bin/redis-server
2.コントローラー、モデル、チャンネルを作成
全てコマンドラインで作成します。
1) コントローラー
rails g controller rooms show
2) モデル
rails g model message content:text
rails db:migrate
3) チャンネル
rails g channel room speak
3. .rbの編集
こちらはActionCableでSubscribeするチャンネルのコードです。
class RoomChannel < ApplicationCable::Channel
def subscribed
stream_from "room_channel"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def speak(data)
Message.create! content: data['message']
ActionCable.server.broadcast 'room_channel', message: data['message']
end
end
こちらは通常のコントローラーでモデルからデータを取り出して表示しているだけです。
class RoomsController < ApplicationController
def show
@messages = Message.all
end
end
ルーターの設定です。mount ActionCable.server => '/cable'というのがポイントで、今後ws://192.168.10.5:28080/cableというエンドポイントに向かってJSクライアントが接続します。
Rails.application.routes.draw do
get 'rooms/show'
# mount /cable as ActionCable consumer endpoint
mount ActionCable.server => '/cable'
end
下記の設定はVirtualBoxに立てたローカルサーバーで動かしているので必要でした。
# allow from all to websocket
ActionCable.server.config.disable_request_forgery_protection = true
# allow form only internal network
config.web_console.whitelisted_ips = '192.168.0.10/26'
4. JavaScriptの作成
//
//= require action_cable
//= require_self
//= require_tree ./channels
(function() {
this.App || (this.App = {});
(function() {
App.room = App.cable.subscriptions.create("RoomChannel", {
connected: function() {
return console.log('connected------');
},
disconnected: function() {
return console.log('disconnectd------');
},
received: function(data) {
alert('message!');
$('#messages').append(data['message']);
return console.log('received------');
},
speak: function(data) {
this.perform('speak',{message: data});
}
});
}).call(this);
// start after document is ready
$(document).ready(function(){
$("input").keypress(function(event){
if ( event.which == 13 ) {
event.preventDefault();
App.room.speak(event.target.value);
}
});
});
5. HTMLの作成
<div class="message">
<p><%= message.content %></p>
</div>
<h1>Chat room</h1>
<div id="messages">
<%= render @messages %>
</div>
<form>
<label>Say something:</label><br>
<input type="text" data-behavior="room_speaker" style="background-color:silver">
</form>
6. 起動
上記のコードはRailsServerで動く設定になっています。
192.168.10.5でVirtualMachineを動かしているので下記のコマンドで動かします。
rails server -b 192.168.10.5