Help us understand the problem. What is going on with this article?

Action Cableの設定でつまずいたこと

行っていること

以下の記事や動画を参考にチャット機能を作成しています。
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
0から手を動かして作るRailsチャットアプリ【チュートリアル】

リアルタイムでのチャット機能を作成する際につまずいたことを、備忘録も兼ねて共有します。
ご指摘やアドバイスがありましたらコメントよろしくお願いします。

やりたいこと

自分(current_user)と他の人で表示方法を変える
スクリーンショット 2020-01-24 17.56.47.png

チャンネルの作成

$ rails g channel chatroom speak
    create  app/channels/chatroom_channel.rb
    create  app/assets/javascripts/channels/chatroom.coffee

つまずいたこと

chatroom_channel.rbから_post.html.erbをrenderで呼び出そうとすると、[ActionView::Template::Error - undefined method 'id' for nil:NilClass] と言われる。→channelからrenderした際にcurrent_userの値を取れていないため

コード一覧

routes.rb
Rails.application.routes.draw do
  root to: 'toppages#index'
  # (省略)

  resources :chatrooms do
    member do
      get :users
    end
  end

  mount ActionCable.server => '/cable'
end
posts/_post.html.erb
<% unless post.user_id == current_user.id %>
  <p style="color:blue;"><%= post.content %></p>
<% else %>
  <p style="color:red;"><%= post.content %></p>
<% end %>
chatroom_channel.rb
class ChatroomChannel < ApplicationCable::Channel
  def subscribed
    stream_from "chatroom_channel"
  end

  def unsubscribed
    # Any cleanup needed when channel is unsubscribed
  end

  def speak(data)
    message = Post.create! content: data['message'], user_id: data['user_id'], chatroom_id: data['room_id']
    template = ApplicationController.renderer.render(partial: 'posts/post', locals: { post: message })
    ActionCable.server.broadcast 'chatroom_channel', message: template
  end
end
chatroom.coffee
# クライアントサイドの処理を受け持つチャンネ
App.chatroom = App.cable.subscriptions.create "ChatroomChannel",
  connected: ->
    # Called when the subscription is ready for use on the server

  disconnected: ->
    # Called when the subscription has been terminated by the server

  received: (data) ->
    $('#posts').append data['message']


    # Called when there's incoming data on the websocket for this channel

  speak: (content, data_user, data_room) ->
    @perform 'speak', message: content, user_id: data_user, room_id: data_room


document.addEventListener 'DOMContentLoaded', ->
  input = document.getElementById('chat_input') 
  data_user = input.getAttribute("data_user")
  data_room = input.getAttribute("data_room")
  button = document.getElementById('chat_button')
  button.addEventListener 'click', ->
    content = input.value
    App.chatroom.speak(content, data_user, data_room)
    input.value = ''
    return
  return

原因

channelからは sessionを使うことが出来ないそうです。
(sessions_helperでcurrent_userを定義している。)

解決方法

channelからcookieは使うことができるそうなので、cookieからユーザー情報を取ってきて、current_user変数に代入。
主にこちらの記事を参考にしました。

cookieの情報からcurrent_userの作成

channels/application_cable/connection.rb
module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    protected

    def find_verified_user
      if verified_user = User.find_by(id: session['user_id'])
        verified_user
      else
        reject_unauthorized_connection
      end
    end

    def session
      cookies.encrypted[Rails.application.config.session_options[:key]]
    end
  end
end
chatroom_channel.rb
# (省略)

  def speak(data)
    message = Post.create! content: data['message'], user_id: data['user_id'], chatroom_id: data['room_id']
    template = ApplicationController.renderer.render(partial: 'posts/post', locals: { post: message, current_user: current_user }) # current_user変数にconnection.rbで取得したcurrent_userを設定
    ActionCable.server.broadcast 'chatroom_channel', message: template
  end

関連リンク

DOMContentLoadedからturbolinks:loadへ変更
Action Cableへのidの受け渡し

参考リンク

Rails5のActionCableで簡易チャットの作成 ~モデルに応じたチャンネルを聴講する方法~

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした