railsでチャット機能

  • 18
    Like
  • 2
    Comment
More than 1 year has passed since last update.

rails 4.2.5
ruby 2.1.3

railsアプリの作成

$ rails new websocket

gemの追加

gemのインストール

$ gem install websocket-rails

gemfileにwesocket-railsを追加

gem `websocket-rails`

これで$ bundle install

websocket-railsで使うものをinstall

$ rails g websocket_rails:install
   create  config/events.rb
      create  config/initializers/websocket_rails.rb
      append  app/assets/javascripts/application.js

development.rbに追加

これを追加しないと、ローカルで動かないっぽい。

config/environments/development.rb
Rails.application.configure do
  config.middleware.delete Rack::Lock
end

作成されたevent.rbに情報を追加する

event.rbはroutes.rbのようなもので、後に定義するjsで呼ばれるリクエストに対して、railsのコントローラーをマッピングしている。

自分の場合は、クライアントでsend_messageというリクエストがあれば、Websocket_message_controller.rbのrecieve_messageメソッドでさばくよってことを書いている。

config/event.rb
WebsocketRails::EventMap.describe do
  # You can use this file to map incoming events to controller actions.
  # One event can be mapped to any number of controller actions. The
  # actions will be executed in the order they were subscribed.
  #
  # Uncomment and edit the next line to handle the client connected event:
  #   subscribe :client_connected, :to => Controller, :with_method => :method_name
  #
  # Here is an example of mapping namespaced events:
  #   namespace :product do
  #     subscribe :new, :to => ProductController, :with_method => :new_product
  #   end
  # The above will handle an event triggered on the client like `product.new`.
  subscribe :send_message, :to => WebsocketMessageController, :with_method => :recieve_message    #追加したところ
end

event.rbで指定したcontrollerを手動で自分で作成する

rails g controller websocket_message

作成したコントローラーにevent.rbで指定したメソッドを追加

先ほど指定したrecieve_messageメソッドの作成

app/controller/websocket_message_controller.rb
class WebsocketMessageController < WebsocketRails::BaseController
  def recieve_message
    message = message();
    broadcast_message :show_message, message
  end
end

message() 

      クライアントからのメッセージを取得する。

broadcast_message(event_name, message, options={}) 

      引数event_nameのイベントとして、全クライアントへ引数dataを送信する。
     
      [event_name] ・・・ 送信するイベント名を指定

      [data] ・・・ 送信するデータを指定

      [options] ・・・ namespaceなどのオプションがある場合に指定

message(),broadcast_messageメソッドはwebsocket-railsの中の決まり事。 

他にもメソッドあります。

表示する用のcontrollerとviewの作成

$ rails g controller messages index

view側のコード

app/view/messages/index.html.erb
<% if user_signed_in? %>

<div id="message_box">
   <p>broadcasting message</p>
   <!-- 送信ボタンを押したらここにメッセージが表示される -->
 </div>
 <input type="text" id="message_input">      <!--フォームの作成 -->
 <input type="button" id="send_message" value="send">  <!--フォーム送信ボタンの作成 -->


 <script>
 $(document).ready(function(e){
   var dispatcher = new WebSocketRails('localhost:3000/websocket'); // WebSocketRailsオブジェクトを作成すると、websocket-railsのサーバーに接続することができる。URLはデプロイする時はちゃんとローカルホストではなくサイトのURLに変更する。

   $(document).on("click", "#send_message", function(e){      //$(document) = HTML でclickイベントが発生したところが、send_message IDの要素を持っていたら、処理をする。という指定が.onを使うことによって指定できる。
     message_text = $("#message_input").val();                //上のmessage_input IDのフォームに入力されたメッセージを.val()メソッドで取り出してmessage_textに入れている
     dispatcher.trigger("send_message", message_text);        //send_messageをリクエストして、websocket_message_controller.rbのrecieve_messageメソッドを呼び出している。  .trigger( "イベント名",パラメーター )
   });

   dispatcher.bind("show_message", function(message){         //.bindでwebsocket_message_controllerで定義したmessageを呼び出して、
     $("#message_box").append("<p>" + message + "</p>");      //message_box IDの中に messageをappend(追加)する。
   });
   });
 });
 </script>

<% else %>
<% end %>


この.bindだけど、何か調べたら.onと同じだから.bind使うより.onを使ってくださいみたいなことが書いてあったから、.onにして確認して見たけど、動作しませんでした。わかる方コメントください。

これで、サイトを見ている人全員でチャットができるようになる。
と思いきや、まだはやい。
おそらく画面は表示されるが、メッセージを送信しても表示できないはず。
そしてデロッパーツールのNetworkで通信を確認すると、双方向通信が、30秒経つと勝手に切れてしまうことがわかる。
それは、websocket-rails gem を入れた時に勝手に入る、
faye-websocketというgemのバージョンを変更してあげないと、うごかない。
ここで僕は訳がわからずハマりしました。

https://github.com/websocket-rails/websocket-rails/issues/379

faye-websocketのバージョン変更

gem 'faye-websocket', '0.10.0'

$ bundle update

これで晴れてチャットができます。

自分はこれとdeviseを使って、ユーザー登録をするところまでできました。
最初deviseとwebsocket-railsを同時に入れようとしたらエラーが出てできなかったと思います。
なので、websocket-railsでチャットが動くのが確認できてから、deviseをいれたらちゃんとできました。

あと自分が実現したいことは、ユーザー間の1対1のラインみたいなやりとりと、チャットの保存。
でも文書が少なく、どうやって良いかわからず。
それは今後の課題で自分でちゃんと理解して試行錯誤してやっていくしかなさそう。