LoginSignup
0
1

More than 3 years have passed since last update.

Action Cableについて

Posted at

背景

Railsでチャット機能の実装はどのようにするのかなと気になって調べてみると「Action Cable」というものを使うと簡単に実装できるとあったので簡単ではあるが、備忘録として自分なりに概要を書こうと思った。

Action Cableとは

WebSocketとRailsのその他の部分をシームレスに統合するためのもの。Action Cable が導入されたことで、Rails アプリケーションの効率の良さとスケーラビリティを損なわずに、通常のRailsアプリケーションと同じスタイル・方法でリアルタイム機能をRubyで記述できます。

実装手順

1.speakというアクションをもつ、ChatRoomチャンネルを作成する
※channels/chat_room.coffeeファイルはいらないので削除する

$ rails g channel chat_room speak

2.app/assets/javascripts/chat.coffeeをchat.jsにrenameし以下を記述する。

chat.js

if(/chat/.test(window.location.pathname)) {
  var path = window.location.pathname.split('/');
  var room_id = path[path.length - 1];
  App.chat_room = App.cable.subscriptions.create({ channel: "ChatRoomChannel", room_id: room_id }, {
    connected: function() {},
    disconnected: function() {},
    received: function(data) {
      $('.messages').append(data['content']);
    },
    speak: function(message) {
      return this.perform('speak', {
        message: message,
        room_id: room_id,
        user_id: $('meta[name="current_user_id"]').attr('content')
      });
    }
  });
  $(document).on('keypress', '[data-behavior~=room_speaker]', function(event) {
    if (event.keyCode === 13) {
      App.chat_room.speak(event.target.value);
      event.target.value = '';
      return event.preventDefault();
    }
  });
}

3.書き込んだ内容をrenderするために、app/views/chat_messages/_chat_message.html.erb を追加します。

_chat_message.html.erb
<div class="message">
  <span class="message__name">
    <%= chat_message.user.name %>:
  </span>
  <% if chat_message.user.id == current_user.id %>
    <div class="message__text message_current_user">
      <div><%= chat_message.message %></div>
    </div>
  <% else %>
    <div class="message__text">
      <div><%= chat_message.message %></div>
    </div>
  <% end %>
</div>

4.chat_room_channel.rbを以下のように編集する。
フロントから送信されたデータを受け取っているのでそれを加工して送信して、先ほど作ったテンプレートを使ってレンダリングするように実装する。

chat_room_channel.rb

class ChatRoomChannel < ApplicationCable::Channel
  def subscribed
    stream_for "chat_room_#{params[:room_id]}"
  end

  def unsubscribed
    # Any clkanup needed when channel is unsubscribed
  end

  def speak(data)
    message = ChatMessage.create(chat_room_id: data['room_id'], user_id: data['user_id'], message: data['message'])
    ChatRoomChannel.broadcast_to "chat_room_#{data['room_id']}", content: render_message(message)
  end

  private
    def render_message(message)
      ApplicationController.renderer.render(partial: 'chat_messages/chat_message', locals: { chat_message: message, current_user: message.user })
    end
end

5.current_user_idはapp/views/layouts/application.html.erbのmetaタグとして設定してそれを読み出すことで取得できるようにする。

application.html.erb


<head>
(中略)
<meta name="current_user_id" content="<%= current_user.id if current_user %>">
(中略)
</head>

※これで完成なのだが自分の場合はここでターボリンクスが悪さをしてエラーが発生したので同じエラーが起きた場合はターボリンクスを無効化してみてください。

0
1
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
0
1