このエントリでは、
PusherとRubyOnRailsで簡単なチャットアプリを作成する流れを示します。

WebSocketを使うと、Webアプリケーションで、
サーバ・クライアント間でリアルタイムな双方向通信を行うことが出来ます。
Pusherというサービスを使うと、
WebSocketに対応したサーバを自前で用意しなくても、
お手軽にWebSocketを使用する事ができるので、
Railsと組み合わせて、簡単なチャットアプリを作ってみます。

Pusher
http://pusher.com

このエントリで作成したソースコードはgithubに上げています。
https://github.com/takemikami/chat_rails_pusher_sample

作成するアプリの概要

作成するアプリは以下の流れで、
チャットのメッセージを送信し、ページに表示することとします。

  1. ブラウザからメッセージ送信
  2. Railsサーバで受信、PusherにPush通知依頼
  3. PusherからブラウザにPush通知
  4. Push通知を受けて、メッセージを表示領域に即時表示

chat_rails_pusher_1

以下の流れでアプリを作っていきます。
・Puhserのアカウントとアプリケーションを作る
・既定の状態のRailsアプリを作る
・チャット画面の枠組みを作る
・サーバサイドの機能を組み込む
・クライアントサイドの機能を組み込む
・チャットの動作確認を行う
・Pusherのキー情報を設定ファイルに移動させる

Pusherのアカウントとアプリケーションを作る

まずは、Pusherのアカウントとアプリを作成していきます。

Pusherのサイトにアクセスする。

Pusher
http://pusher.com

「Create a Free Account」から手順に従って、アカウント作成。
アカウントを作成したら、以下からログインして、Dashbordを表示します。

Pusher: Dashboard
https://app.pusher.com/accounts/sign_in

Your Appsで「+ New app」ボタンを押し、
「chat_rails_pusher_sample」という名称を指定して、
「Create app」を押し、アプリを作成します。

アプリ作成後の画面では、
「Code examples」が表示され、
クライアント側のJavascriptと、
サーバ側の各種言語のサンプルが確認できます。

後ほどの手順では、
ここに表示されるサンプルをコピーして使用していきます。

既定の状態のRailsアプリを作る

ひとまず、既定の状態のRailsアプリを用意します。

次のコマンドでRailsアプリ用のディレクトリを作成します。

$ mkdir chat_rails_pusher_sample
$ cd chat_rails_pusher_sample

以下のとおり「Gemfile」を作成します。

source "https://rubygems.org"
gem 'rails'

次のコマンドでrailsをインストール、Railsアプリを作成します。

$ bundle install --path vendor/bundle
$ bundle exec rails new .

次のコマンドで、開発用Webサーバを起動します。

$ bundle exec rails s

ブラウザで「http://127.0.0.1:3000/」を表示し、
RailsのWelcomeが表示されていることを確認。

チャット画面の枠組みを作る

次に、チャット画面を枠組みを作ります。

次のコマンドで、メインのコントローラーを作成。

$ bundle exec rails g controller chat

「config/routes.rb」に、
チャットのメイン画面のルート、メッセージの送信先ルートを設定します。

Rails.application.routes.draw do
root 'chat#index'
post 'post' => 'chat#post'
**** 省略 ****
end

「app/views/chat/index.html.erb」を編集し、
チャットのメイン画面の枠組みをつくります。

<%= form_tag('/post', :remote => true) do %>
<%= text_field_tag 'message' %>
<%= submit_tag 'send' %>
<% end %>

<div id='messagelog'></div>

前半のform_tagが、メッセージの送信用フォーム
後半のdivタグが、メッセージの表示領域です。

サーバサイドの機能を組み込む

次にサーバサイド側の機能を組み込んでいきます。

pusherのライブラリを使うので、「Gemfile」に以下を追記します。

gem 'pusher'

次のコマンドで、先ほど追記したpusherのgemをインストール。

$ bundle install

PusherのDashbordからRails用のコードを確認します。
Dashbordに表示されているサンプルコードを元に、
以下のように「config/initializers/pusher.rb」を作成。

require 'pusher'

Pusher.url = "http://<あなたのaccess_key>:<あなたのaccess_key_secret>@api.pusherapp.com/apps/<あなたのapp_id>"
Pusher.logger = Rails.logger

gem追加とinitializer配下を修正したので、
ここで、railsのWebサーバは再起動しておきます。

以下のように「app/controllers/chat_controller.rb」を編集します。
ここでは、ブラウザからpostされたメッセージを受け付け、
そのメッセージ情報をpush送信するように、pusherに依頼を行っています。

class ChatController < ApplicationController
def post
Pusher['general_channel'].trigger('chat_event', {
message: params[:message]
})
render :text => 'OK', :status => 200
end
end

クライアントサイドの機能を組み込む

ここまでで、
1. ブラウザからメッセージ送信
2. Railsサーバで受信、PusherにPush通知依頼
3. PusherからブラウザにPush通知
まで実装できたので、
次は、ブラウザ側でPush通知を受け付け、
メッセージ表示領域に追記する部分を実装します。

PusherのDashbordのクライアント側サンプルコードを元に、
以下のように「app/views/chat/index.html.erb」に処理を追記。

<script src="//js.pusher.com/2.2/pusher.min.js" type="text/javascript"></script>
<script type="text/javascript">
// Enable pusher logging - don't include this in production
Pusher.log = function(message) {
if (window.console && window.console.log) {
window.console.log(message);
}
};

var pusher = new Pusher('<あなたのaccess_key>');
var channel = pusher.subscribe('general_channel');
channel.bind('chat_event', function(data) {
var messagelog = document.getElementById('messagelog');
var messagediv = document.createElement('div');
messagediv.innerHTML = data.message;
messagelog.appendChild(messagediv);
});
</script>

**** 省略 ****

チャットの動作確認を行う

ここまでで、チャットアプリの流れは完成したので、動作確認を行います。
2つのブラウザを起動し、
両方のブラウザで「http://127.0.0.1:3000/」を開きます。

一方でメッセージを入力し送信すると、
即時に両方にメッセージが追記されることが確認出来るはずです。

chat_rails_pusher_2

Pusherのキー情報を設定ファイルに移動させる

Pusherのキー情報がソースコードべた書きなのが気持ち悪いので、
最後にキー情報を設定ファイルに移動させておきます。

次のように「config/pusher.yml」を作成。

development:
app_id: <あなたのapp_id>
access_key: <あなたのaccess_key>
access_key_secret: <あなたのaccess_key_secret>

次のとおり「config/initializer/pusher.rb」を修正。

require 'pusher'

config_pusher = YAML.load_file('config/pusher.yml')[Rails.env]
Pusher.url = "http://#{config_pusher['access_key']}:#{config_pusher['access_key_secret']}@api.pusherapp.com/apps/{config_pusher['app_id']}"
Pusher.logger = Rails.logger

次のとおり「app/controllers/chat_controller.rb」を修正。

class ChatController < ApplicationController
def index
config_pusher = YAML.load_file('config/pusher.yml')[Rails.env]
@pusher_access_key = config_pusher['access_key']
end
**** 省略 ****
end

次のとおり「app/views/chat/index.html.erb」を修正。

**** 省略 ****
var pusher = new Pusher('<%= @pusher_access_key %>');
**** 省略 ****

以上。。