Edited at

Rails5のAction Cableの試食

More than 1 year has passed since last update.

Rails5になってAction Cableというものが追加されたので、Websocketが使いやすくなったらしいです。実際にやって見ます


Let's try!


STEP1 プロジェクトのセットアップ

rails newやってbundleまでやってください。省略。


STEP2 コントローラの作成とルーティング

コントローラを適当に作ります。


ターミナル

$ rails g controller home index



config/routes.rb

Rails.application.routes.draw do

root 'home#index'
end


STEP3 Action CableのChannel作成

Action CableのChannelを作成します。これは、いわゆるコントローラだと思ってもらえれば構いません。


ターミナル

$ rails g channel chat


出来上がったChannelを見て見ましょう。


app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel

def subscribed
# stream_from "some_channel"
end

def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
end


名前の通りですが、subscribedがクライアントと接続されたとき、unsubscribedは接続が解除されたときに実行されるメソッドです。

subscribedにはクライアントが受信すべき、ストリームを設定します。

ストリームはルーティングに近いもので、そのストリームに対してデータを流すとそのストリームを受信するようにと設定されたクライアントにデータが届きます。

もう1つWebsocketでクライアント的役割を果たす、app/assets/javascripts/channels/chat.coffeeが出来上がっています。


app/assets/javascripts/channels/chat.coffee

App.chat = App.cable.subscriptions.create "ChatChannel",

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


名前の通り、connectedが接続の繋がった時、disconnectedが接続の解除が起こった時、receivedが受信をした時に実行されるコールバック関数です。


STEP4 とりあえず繋いでみる

Channelの作成は済んだので、ここからはWebsocketを繋いでみましょう。

まずはChannel側から


app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel

def subscribed
stream_from 'chat:message' #ここが変わった
end

def unsubscribed
# Any cleanup needed when channel is unsubscribed
end

def put_message
ChatChannel.broadcast_to('message', 'hello')
end
end


stream_fromによってクライアントが聞くべき、ストリームの名前を指定します。

ChatChannel.broadcast_to('message', 'hello')によって、chat:messageストリームに'hello'を送信しています。ストリームの名前に注意しましょう。

あとChatChannel.broadcast_to('message', 'hello')は普通のコントローラからでも呼び出せます。


app/assets/javascripts/channels/chat.coffee

App.chat = App.cable.subscriptions.create "ChatChannel",

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) ->
console.log(data)

put_message: () ->
@perform('put_message')
return


@perform('put_message')によって、ChatChannelput_messageメソッドを呼び出すことができます。

とりあえず実行してみましょう。

スクリーンショット 2017-01-29 0.03.39.png

インスペクタを使って、put_message()を呼び出します。うまく行くとこんな感じになります。


STEP5 チャットにしよう

もうだいたいやることはわかったので仕上げに取り掛かります。


app/views/home/index.html.erb

<%= form_tag '#', id: 'message' do %>

<%= text_field_tag 'body' %>
<% end %>
<ul id="message-list">
</ul>


app/assets/javascripts/application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files

// listed below.
//
// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
//
// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.
//
// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.
//
//= require jquery
//= require jquery_ujs
//= require turbolinks
//= require_tree .

window.addEventListener('load', () => {
document.getElementById('message').onsubmit = () => {
App.chat.put_message(document.getElementById('body').value);
return false;
}
});



app/assets/javascripts/channels/chat.coffee

App.chat = App.cable.subscriptions.create "ChatChannel",

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) ->
li = document.createElement('li')
li.textContent = data
document.getElementById('message-list').appendChild(li)

put_message: (msg) ->
@perform('put_message', { message: msg })



app/channels/chat_channel.rb

class ChatChannel < ApplicationCable::Channel

def subscribed
stream_from 'chat:message'
end

def unsubscribed
# Any cleanup needed when channel is unsubscribed
end

def put_message(data) #ここが変わった
ChatChannel.broadcast_to('message', data['message']) #ここが変わった
end
end


特にコメントすることはないのですが、@perform('put_message', { message: msg })の第2引数(サーバに送られるデータ)は、ハッシュ/配列じゃないとダメそうです

タブを2つくらい開いてメッセージを送って、一方のタブで入力/送信した内容が他方にも届いていたら完成です!