雀巽の日記帳

雀巽が綴る日常の記録

Rails5.0.0-beta1のActionCableを使って超簡易チャットを実装してみた

Rails 5.0.0-beta1 が December 18, 2015 にリリースされたようです。

公式ブログを爆速で翻訳してくださった方がいるので、そちらも貼っておきます。

qiita.com

WebSocket を扱える Action Cable に興味があったので、早速 Rails 5.0.0-beta1 を入れて、ほぼ写経で超簡易チャットを作ってみました。

Rails 5.0.0-beta1 をインストール

以下のコマンドでインストールできます。

$ gem install rails --pre

Ruby は 2.2.2 以上が必要らしいです。

Redis をインストール

Action Cable では Redis を使用するらしいので、そちらもインストールしておきます。

$ brew install redis

インストールしたらredis-serverと叩いて起動しておきます。

チャット画面の作成

ネットの海をさまよってたらやりたいことを Rails 4 と ActionCable を使ってほぼまんまやってるくださってる記事を見つけました。

nithinbekal.com

ありがたく写経に励みます。

config/routes.rb

Rails.application.routes.draw do
  resources :sessions, only: %i(new create)
  resources :messages, only: %i(index create)
end

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def create
    cookies.signed[:username] = params[:session][:username]
    redirect_to messages_path
  end
end

app/views/sessions/new.html.slim

= form_for :session, url: sessions_path do |f|
  = f.label :username, "Enter a username"
  br
  = f.text_field :username
  br
  = f.submit "Start chatting"

app/controllers/messages_controller.rb

class MessagesController < ApplicationController
  def create
    head :ok
  end
end

app/views/messages/index.html.slim

| Signed in as @
= cookies.signed[:username]
br
br

#messages
br
br

= form_for :message, url: messages_path, remote: true, id: "messages-form" do |f|
  = f.label :body, "Enter a message:"
  br
  = f.text_field :body
  br
  = f.submit "Send message"

erb ファイルは写経する気が起きなかったので、slim に書きなおしました。

これで画面が完成です。次は Action Cable の設定をしていきます。

Action Cable の有効化

先ほど紹介した記事中ではcable/config.ruを作成してbundle exec puma -p 28080 cable/config.ruを実行することでスタンドアローンで Cable サーバーを立ち上げていましたが、Rails 5.0.0-beta1 では デフォルト開発サーバーが Webrick から Puma に変更されているため、同一プロセス上で Action Cable が実行できます。

せっかくなので、bin/rails serverと起動するだけで Action Cable が使えるように設定したいと思います。

config/routes.rb

routes ファイルに以下のルーティングを追加します。

Rails.application.routes.draw do
  match "/websocket", to: ActionCable.server, via: %i(get post)
end

app/assets/javascripts/cable.coffee

次に、cable.coffee ファイルで Websocket サーバを指定します。

@App ||= {}
App.cable = ActionCable.createConsumer("/websocket")

Rails App と同一サーバで Action Cable を起動するため、上記のような記述になります。 開発サーバの設定がデフォルトであればws://localhost:3000/websocketに対してコネクションを要求するようになります。

チャット用 Channel の追加

Consumer に Subscribe させる Channel を追加します。

app/channels/messages_channel.rb

参考サイトに従い MessagesChannel を作成しました。

class MessagesChannel < ApplicationCable::Channel
  def subscribed
    stream_from "messages"
  end
end

チャットメッセージの Broadcasting

チャットメッセージが投稿された際に Channel に Broadcast するように設定します。

app/controllers/messages_controller.rb

class MessagesController < ApplicationController
  def create
    ActionCable.server.broadcast "messages",
      message: params[:message][:body],
      username: cookies.signed[:username]

    head :ok
  end
end

Channel の Subscribe

Consumer に MessagesChannel を Subscribe させます。

app/assets/javascripts/channels/messages.coffee

App.messages = App.cable.subscriptions.create 'MessagesChannel',
  received: (data) ->
    $('#messages').append @renderMessage(data)

  renderMessage: (data) ->
    "<p><b>[#{data.username}]:</b> #{data.message}></p>"

開発サーバの起動

開発サーバをbin/rails serverで起動するとあら不思議、WebSocket を利用したリアルタイムチャットの完成です!

感想

あっという間にリアルタイムチャットが完成しました。 サーバープッシュを初めて実装したので、ほぼ写経だったとはいえ動いた時は感動しました。

今回は認証は不要だったので Connection Identifier については一切設定していませんが、こちらを設定すればコネクションの貼り直しなども簡単に行えそうです。

フロントエンドも含めて Rails のレールに乗って開発するなら、Action Cable を使えばかなり効率的に WebSocket を利用できるような気がします。

まとめ

おおまかに、

  1. Action Cable を有効化する
  2. Channel を作成する
  3. Channel に対する処理を実装する (Server/Client)

と言った手順で Action Cable を使用できました。

また、作成したリポジトリGithub に置いてあります。

github.com

余談

最初読み間違えてて The Haskell Cabal の親戚か何かかと思ってました。

今だに脳内で「Cabal」と読んでしまう。