この記事はアピリッツの技術ブログ「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クラスのメソッドを呼んでみるなりなんなりすれば動くはずです
パターンが膨大すぎて個別の症状に応じて苦戦するのはなんだかインフラエンジニアっぽい感じでした
つまりググっても出てこないエラーとの戦いが結構大変だった