Rails4から追加されたこの機能を使うとstreamingっぽいことやpush配信ぽいことが可能です。
Upgrading to Rails 4 の中で ActionController::Live のsampleコードが記載されていたので試してみました(P.62あたり)。
準備
thread-safeなwebサーバであるpumaなどを利用する必要があります。
# Gemfile gem 'puma' $ bundle
写経
Rails
Rails側は、include ActionController::Live を追加して
pushで配信したい内容を書くだけです。
class TimerController < ApplicationController include ActionController::Live def tick response.headers['Content-Type'] = 'text/event-stream' begin seconds = 0 loop do response.stream.write("data: #{seconds}\n\n") seconds += 1 sleep 1 end rescue IOError # client dsconnected ensure response.stream.close # cleanup end end end
ここでは、loopで回しているだけですが、tenderloveさんのsample のようにFSEventを使ってファイルの変更を検知して表示なんてことも可能です。
developmentではthread safeとして起動しないため下記を変更する必要があります。
# config/environments/development.rb # 追加 config.middleware.delete ::Rack::Lock # 変更 config.eager_load = true
Routing
Rails.application.routes.draw do get '/tick' => 'timer#tick'
フロント
html5のServer-Sent Eventsの実装であるEventSourceを利用します。
<!DOCTYPE html> <html> <head> <title>Timer Example</title> <script src="http://code.jquery.com/jquery.js"></script> <script> $(function() { var timerSource = new EventSource('/tick'); timerSource.onmessage = function(e) { $('#timer').text(e.data); }; }); </script> </head> <body> Timer: <span id="timer"></span> seconds. </body> </html>
Server-Sent Eventsの詳しいところまでは理解できていないのですが、なかなか面白そうです。
・WebSocketsと異なりhttpでやりとりする(素晴らしい!!)
・双方向通信ではない
・IEが未サポート
上記の書き方はeventっぽくないのですが
下記のようにeventを定義してやることも可能です。
rails
response.stream.write "event: update\n"
フロント
timerSource.addEventListener('update', function(e) { $('#timer').text(e.data); });
eventがなければonmessageが動作するようです。
関連
・Upgrading to Rails 4
これとてもよいです。