##行っていること
以下の記事や動画を参考にチャット機能を作成しています。
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
0から手を動かして作るRailsチャットアプリ【チュートリアル】
リアルタイムでのチャット機能を作成する際につまずいたことを、備忘録も兼ねて共有します。
ご指摘やアドバイスがありましたらコメントよろしくお願いします。
##やりたいこと
自分(current_user)と他の人で表示方法を変える
##チャンネルの作成
$ 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
の値を取れていないため
##コード一覧
Rails.application.routes.draw do
root to: 'toppages#index'
# (省略)
resources :chatrooms do
member do
get :users
end
end
mount ActionCable.server => '/cable'
end
<% unless post.user_id == current_user.id %>
<p style="color:blue;"><%= post.content %></p>
<% else %>
<p style="color:red;"><%= post.content %></p>
<% end %>
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
# クライアントサイドの処理を受け持つチャンネ
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の作成
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
# (省略)
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の受け渡し