答えは、websocket-rails gemに関連して、Faye とPleziと同様に YES です。Rails で使用されるものとは異なる、新しいコントローラー クラスを作成する必要があります。
websocket-rails は を継承するWebsocketRails::BaseController
必要がありますが、Rails コントローラーは継承する必要がありますActionController::Base
(通常は、このクラスを継承する ApplicationController を継承することによって)。
Ruby は二重クラス継承をサポートしていません (ただし、モジュールを使用する場合は Mixin が可能です)。
一方、フェイはコントローラーを同じオブジェクト指向の方法で使用しておらず、より多くのオプションがあります。たとえば、websocket イベントをコントローラーの CLASS メソッドにマップすることはできますが、コントローラーの内部メカニズムの一部が壊れる可能性があるため、websocket 接続ごとに Rails コントローラーを初期化する際に問題が発生する可能性があります。たとえば、セッション情報は利用できず、おそらく Rails 固有のメソッドをすべて回避する必要があります。
Plezi では、これらの継承の問題は解消されませんが、Plezi は Controller が持つパブリック メソッドへの Http ルートを自動的に作成するため、Rails メソッドは意図しない方法で公開されます。一方、Plezi コントローラーは、Http と Websocket の両方に応答できます。
Faye と Plezi についても書いた理由は、2014 年 3 月に websocket-rails gem が最後に更新された (CHANGELOG によると) ためです ...
Rails の最新の更新にどれだけ耐えられるか (または生き残ったか) はわかりませんが、先に進むことをお勧めします。
2015 年 11 月現在、Faye がより一般的なオプションであり、Plezi はこの分野の新しいプレーヤーです。私は Plezi の作者です。
編集(コメントへの回答)
Faye と Plezi の両方で、あるユーザーが別のユーザーにメッセージを送信できるようにする必要があります。
Plezi の方が使いやすいと思いますが、これは私が Plezi を書いたからです。Faye を書いた人は、Faye の方が簡単だと思うでしょう。
チャットを実装する最良の方法については、希望する方法に応じていくつかのオプションがあります。
Plezi をインストールして (端末で) 実行すると、plezi アプリケーションのデモ コードを見ることができます。
$ plezi mini my_chat
これは、既存のアプリケーションに Plezi Websocket ブロードキャストを追加するための簡単なハックです。
もし私があなたのデータベースにアクセスできたら、少し違ったやり方をしていたでしょう...しかし、概念実証としては十分です....今のところ.
に次の行を追加しますGemfile
。
gem 'plezi'
plezi_init.rb
ファイルを作成し、config/initializers
フォルダーに追加します。これが今のところ保持されているものです(ほとんどはRails Cookieをハッキングしています。データベースにアクセスできず、フィールドを追加できないためです):
class WebsocketController
def on_open
# this is a Hack - replace this with a database token and a cookie.
return close unless cookies[:_linkedchats_session] # refuse unauthenticated connections
# this is a Hack - get the user
@user_id = decrypt_session_cookie(cookies[:_linkedchats_session].dup)['warden.user.user.key'][0][0].to_s
puts "#{@user_id} is connected"
end
def on_message data
# what do you want to do when you get data?
end
protected
# this will inform the user that a message is waiting
def message_waiting msg
write(msg.to_json) if msg[:to].to_s == @user_id.to_s
end
# this is a Hack - replace this later
# use a token authentication instead (requires a database field)
def decrypt_session_cookie(cookie)
key ='4f7fad1696b75330ae19a0eeddb236c123727f2a53a3f98b30bd0fe33cfc26a53e964f849d63ad5086483589d68c566a096d89413d5cb9352b1b4a34e75d7a7b'
cookie = CGI::unescape(cookie)
# Default values for Rails 4 apps
key_iter_num = 1000
key_size = 64
salt = "encrypted cookie"
signed_salt = "signed encrypted cookie"
key_generator = ActiveSupport::KeyGenerator.new(key, iterations: key_iter_num)
secret = key_generator.generate_key(salt)
sign_secret = key_generator.generate_key(signed_salt)
encryptor = ActiveSupport::MessageEncryptor.new(secret, sign_secret, serializer: JSON)
encryptor.decrypt_and_verify(cookie)
end
end
# IMPORTANT - create the Plezi, route for websocket connections
Plezi.route '/ws', WebsocketController
このアプリに必要な Plezi アプリケーションは、これでほぼすべてです。
ChatsController#create
の直前に、次の行をメソッドに追加するだけrespond_to
です。
WebsocketController.broadcast :message_waiting,
from: @msg.sender_id,
to: @msg.receiver_id,
text: @msg.text,
msg: :chat
サーバーは以上です... さて、クライアントです。
次のスクリプトをchat.html.erb
テンプレートに追加します (または、ターボリンクがスクリプトの初期化を台無しにする可能性があるため、スクリプトをapplication.js
ファイルに追加します...ただし、ユーザーがログインするまで多くの接続を拒否することになります):
<script type="text/javascript">
// Your websocket URI should be an absolute path. The following sets the base URI.
// remember to update to the specific controller's path to your websocket URI.
var ws_controller_path = '/ws'; // change to '/controller/path'
var ws_uri = (window.location.protocol.match(/https/) ? 'wss' : 'ws') + '://' + window.document.location.host + ws_controller_path
// websocket variable.
var websocket = NaN
// count failed attempts
var websocket_fail_count = 0
// to limit failed reconnection attempts, set this to a number.
var websocket_fail_limit = NaN
function init_websocket()
{
if(websocket && websocket.readyState == 1) return true; // console.log('no need to renew socket connection');
websocket = new WebSocket(ws_uri);
websocket.onopen = function(e) {
// reset the count.
websocket_fail_count = 0
// what do you want to do now?
};
websocket.onclose = function(e) {
// If the websocket repeatedly you probably want to reopen the websocket if it closes
if(!isNaN(websocket_fail_limit) && websocket_fail_count >= websocket_fail_limit) {
// What to do if we can't reconnect so many times?
return
};
// you probably want to reopen the websocket if it closes.
if(isNaN(websocket_fail_limit) || (websocket_fail_count <= websocket_fail_limit) ) {
// update the count
websocket_fail_count += 1;
// try to reconect
init_websocket();
};
};
websocket.onerror = function(e) {
// update the count.
websocket_fail_limit += 1
// what do you want to do now?
};
websocket.onmessage = function(e) {
// what do you want to do now?
console.log(e.data);
msg = JSON.parse(e.data)
alert("user id: " + msg.from + " said:\n" + msg.text)
};
}
// setup the websocket connection once the page is done loading
window.addEventListener("load", init_websocket, false);
</script>
終わり。