Posted at

Ruby on Railsとrubymotionでリアルタイムweb構築

More than 5 years have passed since last update.


リアルタイムweb?

リアルタイムにwebの情報をサーバからのpush通知で更新する。

有名どころでいうとFB、Chatwork、Twitterとか。

技術的には方法が大きく3つある。


・ポーリング(Polling)

一定の時間に一度、Ajaxでサーバに接続させ

新しい情報がないかどうか調べる。擬似的なプッシュ型。


・コメット(Comet)

クライアントから送られてきたレスポンスをすぐに返さずに処理中の形を取ってコネクションを張ったままにする。

新着の情報があったタイミングでレスポンスを返す。


・Websocket

HTML5より作られた新しい通信規格。独自のプロトコルを持つ。

先程の2通りのデメリットを補いより効率よく双方向通信が可能。

今回は技術的な流れも含め、Websocketを用いる。


railsでどうやって構築する?

railsを用いる事をmustとするなら調べた中だと多く3つ。


・Live Streming

rails4より導入された Live Streming機能。

HTTPコネクションで行うようなので、Polling/Comet系

Rails側のバージョンアップで今後は進化するのか?


・Node.js + Socket.io の併用

DB周りのみrailsに担当させて、Redis + Node.js + Socket.ioでクライアントとはやり取りをする。

だったらrailsってこだわる必要あるのか?とも思ったり。


・websocket-rails

railsでwebsocketを使用する方法では、一番主流?

https://github.com/websocket-rails/websocket-rails

EventMachine使ってるし、イベント駆動型なので

パフォーマンス的にも大丈夫かなー・・・

今回は一旦 websocket-railsで。実行。


rubymotionでどうやって構築する?

squareが作ってるSocketRocketというライブラリを使う。


インストール

まずはwebsocket-railsから。

gem "websocket-rails"

$ bundle

$ rails g websocket_rails:install

開発環境ではRack::Lockを無効にしないとエラーになるので以下のように設定。


config/environments/development.rb

config.middleware.delete Rack::Lock


次にSocketRocket。

app.pods do

pod 'SocketRocket'
end

これで完了。


実装

まずはwebsocket_rails側から。(※基本は以下見ればわかります)

https://github.com/websocket-rails/websocket-rails

websocket_railsが用意してくれる "/websocket"につなぐ。


test.js

var dispatcher = new WebSocketRails("ws://yourhost/websocket");

dispatcher.on_open = function() {
return console.log("Connection has been established: ");
};

dispatcher.bind('hoge', function(){
alert('fuga');
});

$('#hoge').click(function(){
dispatcher.trigger('hoge.send', 'hogefuga');
});



config/events.rb

WebsocketRails::EventMap.describe do

namespace :hoge do
subscribe :send, :to => HogeController, :with_method => :send
end
end



app/controllers/hoge_controller.rb

class HogeController < WebsocketRails::BaseController

def send
broadcast_message :hoge, message
end
end


ダラダラ書きましたが、上記のような形でクライアントとサーバのやり取りが可能です。

クライアント→サーバでのやりとりは、triggerを使ってjs側で設定し、それをevent.rbに明記してcontroller側に送る。

といった至って簡単な構造。

ちなみにbroadcast_messageとすると全てのクライアントに対して送信してしまうので、分けたい場合はchannelというものを使うと実装可能。

またサーバ→クライアントの通信だけなのであれば、

WebsocketRails[:'channel名'].trigger 'hoge', 'fuga'

とすればchannel名をsubscribeしているものにだけpush通知ができたり。何とも簡単。

次にrubymotion。

url = NSURL.URLWithString("ws://49.212.87.13:3006/websocket")

@socket = SRWebSocket.alloc.initWithURLRequest(NSURLRequest.requestWithURL(url))
@socket.delegate = self
@socket.open

def webSocket(webSocket, didReceiveMessage:message)
p message
end

っていう感じに書いておけば、rakeしたときに通信してくれる。

rails側でlog/websocket_rails.logのファイルを確認してみると確かにrubymotionからもwebsocketで繋がれている。

その他はそれぞれのgithubでも見ながら追加していってください。

参考文献