##はじめに
私は、現在、Rails5でポートフォリオ作成中の初学者です。
Action Cableを用いてDM機能(チャット機能)を実装しているのですが、
チャットを送った後、リロードしないと送ったメッセージが表示されません。
##実装の参考にした記事
Rails 5 + ActionCableで作る!シンプルなチャットアプリ(DHH氏のデモ動画より)
[Rails]ActionCableを使用してリアルタイムチャットの実装
リアルタイムチャットは誰でもつくれるAction CableでDM機能を作ろう
など
##メッセージ送信後のターミナル出力結果
出力結果はこちらです。
※見やすいように適宜改行しています。
Terminal
1DirectMessage Create (0.5ms) INSERT INTO "direct_messages" ("user_id", "room_id", "message", "created_at", "updated_at") VALUES (?, ?, ?, ?, ?) [["user_id", 4], ["room_id", 6], ["message", "そそそ"], ["created_at", "2021-04-13 04:18:35.981227"], ["updated_at", "2021-04-13 04:18:35.981227"]] 2 ↳ app/channels/room_channel.rb:13 3 (3.4ms) commit transaction 4 ↳ app/channels/room_channel.rb:13 5Could not execute command from ({"command"=>"message", "identifier"=>"{\"channel\":\"RoomChannel\",\"room\":6}", "data"=>"{\"direct_message\":\"そそそ\",\"action\":\"speak\"}"}) 6[RuntimeError - Circular dependency detected while autoloading constant ApplicationJob] 7: /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:508:in `load_missing_constant' 8| /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/activesupport-5.2.5/lib/active_support/dependencies.rb:195:in `const_missing' 9| /home/ec2-user/environment/enrich-ity/app/jobs/application_job.rb:1:in `<main>' | /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/bootsnap-1.7.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:59:in `load' 10| /home/ec2-user/.rvm/gems/ruby-2.6.3/gems/bootsnap-1.7.3/lib/bootsnap/load_path_cache/core_ext/kernel_require.rb:59:in `load'
調べたところ、Railsでは一度読み込んだファイルをキャッシュして2回目は読み込まないようにしているため、このようにエラーがでるみたいです。
[RuntimeError - Circular dependency detected while autoloading constant ApplicationJob]:
上記記事を参考に色々試行錯誤しましたが解決できませんでした。
##ソースコード
※リロードすればメッセージを表示することは可能なので、viewファイルの記述は間違っていないと思います。
#######db/schema.rb
create_table "direct_messages", force: :cascade do |t| t.integer "user_id", null: false t.integer "room_id", null: false t.string "message", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false end
#######rooms_controller.rb
class Public::RoomsController < ApplicationController before_action :authenticate_user! def create @room = Room.create(:name => "DM") @entry1 = Entry.create(:room_id => @room.id, :user_id => current_user.id) @entry2 = Entry.create(params.require(:entry).permit(:user_id, :room_id).merge(:room_id => @room.id)) redirect_to room_path(@room.id) end def show @room = Room.find(params[:id]) if Entry.where(:user_id => current_user.id, :room_id => @room.id).present? @direct_messages = @room.direct_messages @entries = @room.entries else redirect_back(fallback_location: root_path) end end end
#######cable.js
// Action Cable provides the framework to deal with WebSockets in Rails. // You can generate new channels where WebSocket features live using the `rails generate channel` command. // //= require action_cable //= require_self //= require_tree ./channels (function() { this.App || (this.App = {}); /* global ActionCable */ App.cable = ActionCable.createConsumer(); }).call(this);
#######room.coffee
document.addEventListener 'turbolinks:load', -> if App.room App.cable.subscriptions.remove App.room App.room = App.cable.subscriptions.create { channel: "RoomChannel", room: $('#direct_messages').data('room_id') }, connected: -> disconnected: -> received: (data) -> $('#direct_messages').append data['direct_message'] speak: (direct_message) -> @perform 'speak', direct_message: direct_message $(document).on 'keypress', '[data-behavior~=room_speaker]', (event) -> if event.keyCode is 13 App.room.speak event.target.value event.target.value = '' event.preventDefault()
#######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 #こっちの書き方だとメッセージをcreateできない # if verified_user = User.find_by(id: cookies.encrypted[:user_id]) # verified_user # else # reject_unauthorized_connection # end verified_user = User.find_by(id: env['warden'].user.id) return reject_unauthorized_connection unless verified_user verified_user end end end
#######room_cannel.rb
class RoomChannel < ApplicationCable::Channel def subscribed # stream_from "some_channel" stream_from "room_channel_#{params['room']}" end def unsubscribed # Any cleanup needed when channel is unsubscribed end def speak(data) DirectMessage.create! message: data['direct_message'], user_id: current_user.id, room_id: params['room'] end end
#######application_job.rb
class DirectMessageBroadcastJob < ApplicationJob queue_as :default def perform(direct_message) # マルチスレッド処理対策?書いても効果なし # Rails.application.eager_load! ActionCable.server.broadcast "room_channel_#{direct_message.room_id}", message: render_direct_message(direct_message) end private def render_direct_message(direct_message) # マルチスレッド処理対策?書いても効果なし # Rails.application.eager_load! ApplicationController.renderer.render(partial: 'direct_messages/direct_message', locals: { direct_message: direct_message }) end end
#######direct_message_broadcast_job.rb
class DirectMessageBroadcastJob < ApplicationJob queue_as :default def perform(direct_message) ActionCable.server.broadcast "room_channel_#{direct_message.room_id}", direct_message: render_direct_message(direct_message) end private def render_direct_message(direct_message) ApplicationController.renderer.render(partial: 'direct_messages/direct_message', locals: { direct_message: direct_message }) end end
#######direct_message.rb
class DirectMessage < ApplicationRecord belongs_to :user belongs_to :room has_many :notifications validates :message, presence: true after_create_commit { DirectMessageBroadcastJob.perform_later self } end
#######config/application.rb
require_relative 'boot' require 'rails/all' # Require the gems listed in Gemfile, including any gems # you've limited to :test, :development, or :production. Bundler.require(*Rails.groups) module EnrichIty class Application < Rails::Application # Initialize configuration defaults for originally generated Rails version. config.load_defaults 5.2 config.action_view.field_error_proc = Proc.new { |html_tag, instance| html_tag } config.i18n.default_locale = :ja config.time_zone = 'Tokyo' config.active_record.default_timezone = :local # マルチスレッド処理対策?書いても効果なし config.eager_load_paths += %W(#{config.root}/.rvm/gems/ruby-2.6.3/gems/activesupport-5.2.5/lib/active_support/dependencies.rb) # Settings in config/environments/* take precedence over those specified here. # Application configuration can go into files in config/initializers # -- all .rb files in that directory are automatically loaded after loading # the framework and any gems in your application. end end
2日間このエラーと戦っています。
初学者故に拙い知識での質問になりますが、
ご回答のほど、何卒よろしくお願いいたします。
回答1件
あなたの回答
tips
プレビュー
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。