17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

ActionCable の README を読んでチャットアプリを作ってみた

Posted at

Rails 5 の目玉(?)機能である ActionCable を触ってみようと、README を読んで単純なチャットアプリを作ってみました。簡単な説明とサンプルコードを載せます。

ActionCable

概要

WebSocket と REST である Rails を統合させた、Rails にリアルタイム機能を追加するためのものです。クライアントサイド (JS) と サーバーサイド (Ruby) の両方のフレームワークを提供します。

WebSocket?

WebSocket は RFC6455 で定義されている、Web でリアルタイム通信を行うための通信技術です。最初にハンドシェイクと呼ばれる HTTP 通信を行うのですが、それ以降はサーバーとクライントを接続しっぱなしにして、ステートフルに TCP 通信を行います。WebSocket の利点は主に 2 つです。

  1. サーバープッシュが可能(リアルタイム)
  2. HTTP 通信よりオーバーヘッドが小さい(軽量)

とにかく、軽量でリアルタイム性が高いのが売りです。また、以前はサーバープッシュを実現するために Comet などの技術がありましたが、それに比べて「シンプル」という利点もあります。
ただ、ステートフルなので、 REST な Rails に組み込むにはちょっと考えないといけなかったのですが、そこを今回 ActionCable がまるっとやってくれているようです。

サンプル

概要

ActionCable のサンプルとして、「ユーザー名を入れると単一のチャットルームにログインして、チャットができる」という超単純なチャットアプリを作りました。

デモ

こんな感じです!しょぼすぎてあれですが、、一人がポストすると他の Client (ActionCable では Consumer と呼びます) にも、リアルタイムにプッシュ通知されていることがわかります!

demo4.gif

実装

ActionCable がほとんどやってくれるので、実装はとても単純です。

クライアントサイド

クライアントサイドは、ActionCable を使う準備をして、

app/assets/javascripts/channels/cable.coffee
#= require action_cable
#= require_self
#= require_tree .

@App = {}
App.cable = ActionCable.createConsumer()

以下の4つのメソッドを定義するだけです。

app/assets/javascripts/channels/chat.coffee
App.posts = App.cable.subscriptions.create 'ChatChannel',
  connected: ->
    setTimeout =>
      @perform 'subscribed'
    , 1000

  received: (data) ->
    $("[data-channel='posts']").append(data.post)

  rejected: ->
    @perform 'unsubscribed'

  disconnected: ->
    @perform 'unsubscribed'

App.cable.subscriptions.create 'ChatChannel'ChatChannel を subscribe する準備をし、subscribe した際の動作をそれ以降に定義しています。これらのメソッドは次のタイミングで hook されます。

メソッド 呼ばれるタイミング
connected WebSocket サーバーに接続する際
received WebSocket サーバーからデータがプッシュされた際
rejected WebSocket サーバーに接続を拒否された際
disconnected WebSocket サーバーと接続が切れた際

@perform 'subscribed'ChatChannel#subscribed,
@perform 'unsubscribed'ChatChannel#unsubscribed が呼ばれます。では、#subscribed, #unsubscribed を定義しましょう。

チャンネル(サーバーサイド)

クライアントサイドで準備した ChatChannel の動作を実装します。

app/channels/chat_channel.rb
class ChatChannel < ApplicationCable::Channel
  def subscribed
    stop_all_streams
    stream_from 'sample_chat_room'
  end

  def unsubscribed
    stop_all_streams
  end
end

stop_all_streams で全てを unsubscribe します。
そして、stream_from で subscribe を開始します。引数には subscribe する broadcasting を指定します。今回は毎回、同じ文字列を渡していますが、チャットでいうとルーム名などを渡すイメージです。
チャンネルの実装はこれだけです。

broadcast する内容の定義

先程も紹介したように WebSocket の最大の魅力はサーバープッシュです。そのプッシュする内容を定義します。

app/models/post.rb
class Post < ActiveRecord::Base
  after_commit do
    NewPostJob.perform_later(self)
  end

  ...
end
app/jobs/new_post_job.rb
class NewPostJob < ApplicationJob
  def perform(post)
    ActionCable.server.broadcast 'sample_chat_room',
      post: PostsController.render(partial: 'posts/post', locals: {post: post})
  end
end

本アプリでは、メッセージを送った際に Post が作成されるのですが、その際に NewPostJob を作成して ActionCable.server.broadcast を呼んでいます。 (どのような方法でもとにかく ActionCable.server.broadcast ... を呼べば OK です)

第一引数に broadcasting 名、第二引数に配信するデータを渡します。これで、sample_chat_room を購読している全 Consumer にデータをプッシュします!

そして、データを受信した各クライアントは received メソッドを実行します。

設定ファイル

あとは設定をちょちょっとするだけです!

config/cable.yml
production: &production
  # ....
development: &development
  adapter: redis
  url: redis://localhost:6379
test: *development
config/environments/development.rb
Rails.application.configure do
  ...
  config.action_cable.url = 'ws://localhost:28080'
end
app/views/layouts/application.html.erb
<%= action_cable_meta_tag %>
cable/config.ru
require ::File.expand_path('../../config/environment',  __FILE__)
Rails.application.eager_load!

run ActionCable.server

サーバーは以下のコマンドで起動します。

bundle exec puma -p 28080 cable/config.ru

以上です!

使ってみて

実装しなければいけない部分はほとんどなく、何も意識しないで WebSocket が使えるようになるので、とても便利だなと感じました。以前、EM-WebSocket を使って同じようにチャットアプリを作ったことがありますが、その時に比べると圧倒的に楽です。

あとはどういうケースで WebSocket を使うか、パフォーマンスはどうかが気になりますが、ActionCable とはまた別の問題ですかねー?

また、今回は README をまねして書いたので、本当に基本的な機能しか使ってないですが、もっと色々な便利機能がありそうなので、もっと深ぼってみたいです!

それでは!

17
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
17
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?