LoginSignup
5
6

More than 5 years have passed since last update.

websocket-railsでチャネルに対してtriggerしても、サーバ側でイベントルーティングされない

Last updated at Posted at 2016-03-23

概要

チャットルームのように、特定の部屋に入っているユーザにのみメッセージを送受信しようと、WebScocket-railsのチャネル機能を利用しようとしてハマったのでメモ。

ruby 2.2.2
rails 4.2.6
websocket-rails 0.7.0 712fd4e

結論

タイトルおよび、下記参考URLに記載されている通り、チャネルに対してtriggerしても、サーバ側でイベントルーティングされない。

このため、trigger(javascript ⇒ Railsの送信)は、チャネルではなく大元のディスパッチャに対して行い、bind(Rails ⇒ javascriptの送信)は、チャネル毎に行うのが良いと思われる。

詳細

特定のチャネルに接続しているクライアントに対してのみデータを送受信するには、以下のchannerl_dispatcherように、特定のチャネル名を指定したディスパッチャを作成する。

chat.js
ws_dispatcher = new WebSocketRails("localhost:3000/websocket");
channel_dispatcher = ws_dispatcher.subscribe(room_name);

ただし、

chat.js
ws_dispatcher = new WebSocketRails("localhost:3000/websocket");
channel_dispatcher = ws_dispatcher.subscribe(room_name);

channel_dispatcher.trigger("new_message", {msg_body: comment});

channel_dispatcher.bind("new_message", function(message){
// 以下省略

などとした場合、events.rbにはnew_messageイベントは入ってこなかった。

この場合でも、複数のブラウザ間でルーム内に限定したメッセージの送受信は実際に動作していたため、events.rbを通らずともjavascript間でtrigger ⇒ bindできているようであった。
(あくまでもチャットは動いているため、events.rb⇒チャット用コントローラを経由しているはずと思い込んでしまう可能性があるので注意)

websocket-railsのwikiによると、chanelを利用した場合は、イベントルーティングの対象外となるが仕様のようだ。

結局、triggerはチャネルを利用せず、メッセージにチャットルームを表す識別子を含めた上で大元のディスパッチャを経由してサーバへ送信、コントローラ内でチャットルームを区別して、ルーム毎のチャネルに対してcastするようにするのが良いと思われる。

event.rb
  subscribe :new_message, to: WebsocketChatController, with_method: :new_message
chat_controller.rb
  def new_message
    # クライアントからのメッセージを取得
    recieve_message = message()
    WebsocketRails[recieve_message[:room_name]].trigger(:cast_new_message, recieve_message)
  end
chat.js
  WebSocketRails("localhost:3000/websocket");
  channel_dispatcher = ws_dispatcher.subscribe(room_name);

  // メッセージ送信時の処理
  $('#send').click(function(){
  // room_name = document.getElementById("room_name").innerText;
    comment = $("#comment").prop("value");
    ws_dispatcher.trigger("new_message", {room_name: room_name, user_name: user_name, msg_body: comment});
  });

  // メッセージ受信時の処理
  channel_dispatcher.bind("cast_new_message", function(message){
    message_li = document.createElement("li");
    message_li.textContent = message.room_name + " | " + message.user_name + " | " + message.msg_body;
    document.getElementById("chat_area").appendChild(message_li);
  });

(上記では、大元のディスパッチャに送るか、チャネル毎のディスパッチャに送るかで、"new_message"と、"cast_new_message"とにイベント名を分けているが、判りやすくするためそうしているだけで、同じイベント名でも問題はないはず)

参考

[websocket-rails wiki :Working with Channels]

感謝

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6