[Rails] Action Cableの実装方法

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を操作できるようになりました。

Related Posts