如何从控制器或模型调用ActionCable方法 – “未初始化的常量QuizSession :: App”错误

我正在尝试使用带有2个用户的Ruby on Rails编写一个简单的测验应用程序,他们可以看到不同的视图:

  • 测验主持人视图显示当前问题和“下一个问题” – 按钮(他应该为观众投射到墙上)和
  • 参与者视图显示4个按钮,其中包含与当前问题相对应的答案选项(因此,受众可以通过智能手机参与测验)。

我就是这样,我正在尝试使用ActionCable将这4个答案按钮广播到我的频道,但是当我尝试调用我在频道中定义的方法时,我得到错误"uninitialized constant QuizSession::App"

这些是我为启用ActionCable而采取的步骤:

1)我在/app/channels/quiz_data_channel.rb中生成了一个新频道:

 class QuizDataChannel  # Called when the subscription is ready for use on the server disconnected: -> # Called when the subscription has been terminated by the server received: (data) -> # Called when there's incoming data on the websocket for this channel $('answer-buttons').append(data.partial) send_data: -> @perform 'send_data' 

2)然后我在app / models / services / quiz_data_creation.rb中创建了一个新服务:

 module Services class QuizDataCreation def initialize(user) self.user = user end def create create_quiz_data broadcast_creation end private attr_accessor :user, :answers def create_quiz_data #not sure if this will work @quiz_session = user.quiz_session self.answers = @quiz_session.quiz.questions[@quiz_session.current_question_index].answers end def broadcast_creation QuizDataBroadcastJob.perform_now(answers) end end end 

3)然后我在/app/jobs/quiz_data_broadcast_job.rb上创建了一个新工作:

 class QuizDataBroadcastJob < ApplicationJob queue_as :default def perform(answers) ActionCable.server.broadcast('quiz_data', data: render_answer_options(answers)) end private def render_answer_options(answers) answers.each do |answer| ApplicationController.render( #render student/quiz_question page and render as many answer_option partials as needed partial: 'pages/student/answer_option', locals: {answer: answer} ) end end end 

4)我在我的routes.rb中安装了ActionCable:

 mount ActionCable.server => '/cable' 

5)最后我试图通过在我的应用程序的其他地方调用send_data函数来广播数据:

 def send_current_question App.quiz_data.send_data <--- this is apparently where the error gets thrown end 

我想知道的是:

  • 我该如何解决这个错误?
  • 问题是我还没有正确建立套接字连接?

我已经阅读了3个ActionCable指南并观看了2个指南video – 因为它们中的大多数似乎都是关于聊天应用程序(在我看来是一对一连接)我现在对于如何让我的应用程序在我需要的一对多广播时尚。

我是Rails的新手,所以任何指针都会受到赞赏! 🙂

WebSockets的设计使您无论是构建一对一,多对一,一对多还是多对多function都无关紧要。 原因是作为渠道的发布者,您不知道谁订阅了它,因此无论是1个还是1000个用户,他们都将收到已发布的消息。

至于为什么你得到错误, App对象是一个JavaScript对象(看你如何在coffeescript文件中访问它),所以你不能在Ruby代码中使用它。

您的Ruby代码(后端)中没有提供App对象,因为它应该是客户端(用户)与服务器(后端)通信的方法,这就是它在您的coffeescript代码中初始化的原因。

因此,您需要通过将单击处理程序附加到按钮来调用send_data方法。 让我们在你的HTML中说你的按钮看起来像:

  

在您的客户端代码(coffeescript)中,您将执行以下操作:

 $('#broadcast-button').on 'click', (e) -> App.quiz_data.send_data() 

因此,当用户单击该按钮时,将调用send_data方法。

至于为什么你得到错误,App对象是一个JavaScript对象(看你如何在coffeescript文件中访问它),所以你不能在Ruby代码中使用它。

您的Ruby代码(后端)中没有提供App对象,因为它应该是客户端(用户)与服务器(后端)通信的方法,这就是它在您的coffeescript代码中初始化的原因。

正如@Laith Azer指出的那样, 不可能从控制器或模型中调用CoffeeScript方法(因为它代表前端),但我的所有CoffeeScript方法send_data确实如此,在后端调用它的对应方:

 #/app/assets/javascripts/channels/quiz_data.coffee: App.quiz_data = App.cable.subscriptions.create "QuizDataChannel", ... send_data: -> @perform 'send_data' 

所以可能的是直接调用这个后端方法:

 #In some controller or model: QuizDataChannel.send_data(current_user) 

为了实现这一点,我们需要将ActionCable通道中的方法更改为类方法:

 #/app/channels/quiz_data_channel.rb: class QuizDataChannel < ApplicationCable::Channel def self.send_data(current_user) #self. makes it a class method new_quiz_html = Services::QuizDataCreation.new(user: current_user).create #change "some_room" to the room name you want to send the page on ActionCable.server.broadcast("some_room", html: new_quiz_html) end end 

剩下的就是接收这个html页面并显示它:

 #/app/assets/javascripts/channels/quiz_data.coffee: App.quiz_data = App.cable.subscriptions.create "QuizDataChannel", ... send_data: -> @perform 'send_data' received: (data) -> # This will replace your body with the page html string: $('body').html(data.html)