読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

socket.ioとRailwayJSでモデルとsocketを対応させる

やりたいこととしては
・chats/1
・chats/2
などのshowのアクションに対して、オブジェクトとsocketを一対一対応させたい。
だからchats/1でのAさん、Bさんの会話はchats/2のCさん、Dさんの会話とは区別され、Aさんの発言をbroadcastしてもBさんにしか見えないようにしたい。

Room機能を使う

https://github.com/Jxck/socket.io/wiki/Rooms

socket.ioのroom機能を使う。これによって区別する。

どうやって分けるか?


当初、app.jsに書くべきコードをcontroller/showのアクションに書けば解決するのではないかと思った。つまりshowアクションの中で
socket.join(params.id)のようにするということ。

しかし、この方法ではうまくいかなかった。
どういうふうにうまくいかなかったか説明するのが難しい。通ることは通るのだが挙動が少し変だったり、サーバログを見るとconnectionが増大しているようだった。
おそらく、簡単に言うとsocketのサーバサイドの設定はあくまでのイベントの登録なので全アプリ中で起動時に一度呼べばよく、これをリクエストのたびに呼ぶとイベントがどんどん登録されていく、ということだと思う。

config/initializer/socket.coffee

app.io = require('socket.io').listen(app)
app.io.sockets.on 'connection', (socket)->

  socket.on "enterChat",(chatid)->
    socket.join chatid
    socket.set 'chatid', chatid

  socket.on "disconnect", ->
    socket.get 'chatid',(err,chatid)->
      socket.leave(chatid)
     

public/javascripts/client.js

// TRANSFER
TRANSCEIVER.enterChat = function(){
    id = location.href.split("/").pop();
    socket.emit("enterChat",id);
};

このように、サーバ側でsocketを切り替えるのではなく、一度chat画面に遷移したのちにそのURLをクライアント側から送ってやって、roomを切り替えることとした。もちろんlocation.href.split("/").pop()の部分はアテで、必ずmongoのidであることをvalidateしないといけない。