その他
    ホーム 技術発信 DoRuby ActionCable実装しようwith webpack
    ActionCable実装しようwith webpack
     

    ActionCable実装しようwith webpack

    この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

    Action Cableをイケてる構成のrailsで使いこなそう

    ActionCable 使ってますか?

    Rails5以降から導入されたActionCable
    公式ドキュメントではチャットの実装などで使われていますが、色々な使い方ができそうです
    sidekiqに投げた処理の結果を非同期で受信するとか

    執筆時点では世の中に知見が多くなかったので実装体験記を残します

    導入

    rails g channel hoge_channelでActionCable導入に必要なアレコレが生成されるよ
    ただしcoffee scriptだしSprocketsのアセットパイプラインに乗る形でフロントのスクリプトが吐き出される
    (Rails5.2の場合)

    うちの案件はwebpack導入してるしcoffe scriptなんて書いた事無い
    そんな場合は下記コマンドでライブラリを導入しましょう

    yarn add actioncable
    または
    npm install actioncable

    そしてベースとなるcable.jsはこんな感じに
    自分はapp/javascripts/channelsディレクトリに設置しました

    # app/javascripts/channels/cable.js
    
    import cable from “actioncable”;
    
    let consumer;
    
    function createChannel(...args) {
      if (!consumer) {
        consumer = cable.createConsumer();
      }
      return consumer.subscriptions.create(...args);
    }
    
    export default createChannel;

    各チャンネルのjsはこんな感じ

    # app/javascripts/channels/test_channel.js
    import createChannel from “./cable”;    //cable.jsのパスは適宜変更してください
    $(function(){
      const channel = createChannel(“TestChannel”, {
        received(message) {
          alert(mesage); # この辺に受信時の処理を色々書く、今回は受信したものを取り敢えずブラウザにアラートとして表示する
        }
      });
    
      // rubyのactioncableで実装した処理を()呼ぶ
      function method_name(message) {
         channel.perform(“method_name”, { message });
      }
    });
    

    ruby側の実装は公式ドキュメントで紹介されている実装から特に変更点はないです

    設定

    よ~し取り敢えず検証用にデータを受信したらブラウザのアラートに出す機能作ったので動かしてみるか~
    おや…動かん…エラーが出てるな

    設定に不足がある場合はブラウザのデバッグコンソールに下記のようなエラーが表示されます

    WebSocket handshake: unexpected response code: 502
    

    または

    WebSocket connection to 'wss://example.com' failed: WebSocket is 'test channel~js'
    closed before the connection is estrablished.

    色々な記事にdockerで動かしている場合は専用のコンテナ建てろみたいなことを書いていましたが検証の結果不要でした
    自分の場合 config.reload_classes_only_on_change が false になっていました
    windiwsで開発していた時に変更がホットリロードされなかったのでここの設定弄ったのですがaction_cableの挙動にかかわるようです

    その他設定

    config/cable.yml でdevelop環境もredisを使用する
    
    development:
      adapter: redis
      url: redis://10.10.3.153:6381 => 方法は自由ですがsidekiqやセッション情報とは異なるURLになるように工夫しましょう
      channel_prefix: appname_development
    
    test:
      adapter: async
    
    production:
      adapter: redis
      url: redis://10.10.3.153:6381
      channel_prefix: appname_production
    config/environment/production.rbで自分ドメインからのリクエストを許可する
    
    config.action_cable.allowed_request_origins = ['https://rubyonrails.com', %r{http://ruby.*}]
    config/application.rb でrailsアプリケーション上にマウントするパスを指定する
    
    class Application < Rails::Application
      config.action_cable.mount_path = '/websocket'
    end 
    
    config/routes.rbにマウントするパスを指定する方法を紹介する記事も見かけましたがたぶんこっちの方が良いと思います
    viewファイルのヘッダーに<%= csrf_meta_tags %>を記載する

    その他開発環境の設定や本番サーバーの構成によって何かしらの設定が必要になる場合があります
    nginxのconfigファイルにリクエストヘッダーの設定書くとか…

    うまくAction Cableが動けばRailsコンソール立ち上げて用意したchannelクラスのメソッドを呼んでみるなりなんなりすれば動くはずです
    パターンが膨大すぎて個別の症状に応じて苦戦するのはなんだかインフラエンジニアっぽい感じでした
    つまりググっても出てこないエラーとの戦いが結構大変だった