JQueryは古いテクノロジーとはいえ、さくっと動くものを作るときは異常に簡単です。 古いテクノロジーは悪ではなく適材適所で使っていくのが大事だと思っています。
まずは、最初からあるapp/assets/javascripts/cable.jsを該当layoutで読み込みます。
# app/assets/javascripts/application.js ... //= require cable.js
全部のViewでApp.cableを呼ぶ必要はないのでcontent_forでActionCableとの通信をとるViewだけJSを走らせるようにします。
#app/views/layouts/application.html.erb <head> ... <%= yield :page_scripts %> </head>
JSでは、App.cableにイベントを登録していきます。 引数のchannelにはクラス名、引数を渡すとparamsに入ってサーバ側で処理できます。this.performを使ってクラス内のメソッドを呼ぶことができます。development環境では別プロセスで動作確認ができないのでsetTimeoutを用いてテストしています。
<% content_for :page_scripts do %>
<script>
$(function(){
// Subscrubung host status
$('span.host-status')
.filter(function(i){
return $(this).text() !== "terminated";
})
.each(function(i){
var hostId = $(this).data('hostId');
var self = this;
App.cable.subscriptions.create({channel: "HostStatusChannel", host_id: hostId}, {
connected: function(){
console.log('connected');
//var self = this;
//setTimeout(function(){
// console.log('say now');
// self.perform("say");
//}, 1000);
},
received: function (data) {
var currentStatus = $(self).text();
if(data.status !== currentStatus){
$(self).fadeOut(500, function(){
$(self).text(data.status);
$(self).fadeIn();
});
}
},
});
});
});
</script>
<% end %>
HTML部分は下記のような感じ。
<span class="host-status" data-host-id="<%= host.id %>"><%= host.status %></span>
で最後になりますが、ActionCableを継承したクラスです。subscribedがconnectionとともに走ります。 stream_for MODELでモデルに関係したチャネルが接続されます。 そして、broadcast_to(MODEL, object)でそのモデルへの接続を確率したチャネルにプッシュすることができます。
# app/channels/host_status_channel.rb
class HostStatusChannel < ApplicationCable::Channel
def subscribed
host = Host.find(params[:host_id])
stream_for host
end
def say # for testing
HostStatusChannel.broadcast_to(Host.find(1), "hi")
end
end
これでダイナミックにDOMを操作できるようになりました。