我正在尝试使用带有2个用户的Ruby on Rails编写一个简单的测验应用程序,他们可以看到不同的视图:
我正在尝试使用ActionCable将这4个答案按钮广播到我的频道,但是当我尝试调用我在频道中定义的方法时,我收到错误"uninitialized constant QuizSession::App"
。
这些是我为启用ActionCable而采取的步骤:
1)我在/app/channels/quiz_data_channel.rb中生成了一个新频道:
class QuizDataChannel < ApplicationCable::Channel
def subscribed
stream_from "quiz_data"
end
def unsubscribed
# Any cleanup needed when channel is unsubscribed
end
def send_data
Services::QuizDataCreation.new(user: current_user).create
end
end
# /app/assets/javascripts/channels/quiz_data.coffee:
App.quiz_data = App.cable.subscriptions.create "QuizDataChannel",
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) ->
# 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个指南视频 - 因为它们中的大多数似乎是关于聊天应用程序(在我看来是一对一连接)我现在对于如何将我的应用程序设置为以我需要的一对多广播方式工作。
我是Rails的新手,所以任何指针都会受到赞赏! :)
答案 0 :(得分:0)
WebSockets的设计使您无论是构建一对一,多对一,一对多还是多对多功能都无关紧要。原因是作为渠道的发布者,您不知道谁订阅了它,因此无论是1个还是1000个用户,他们都将收到已发布的消息。
至于你收到错误的原因,App
对象是一个JavaScript对象(看你在coffeescript文件中如何访问它),所以你不能在Ruby代码中使用它。
您的Ruby代码(后端)中没有提供App
对象,因为它应该是客户端(用户)与服务器(后端)通信的方法,这就是它被初始化的原因在你的coffeescript代码中。
因此,您需要通过将单击处理程序附加到按钮来调用send_data方法。让我们在你的HTML中说你的按钮看起来像:
<button id="broadcast-button">Broadcast</button>
在您的客户端代码(coffeescript)中,您将执行以下操作:
$('#broadcast-button').on 'click', (e) ->
App.quiz_data.send_data()
因此,当用户点击该按钮时,将调用send_data方法。
答案 1 :(得分:0)
至于你收到错误的原因,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)