Rails Как использовать ActionCable для рендеринга всей новой страницы на "получены:"
Я пытаюсь создать приложение для викторины (не одностраничное приложение) с двумя типами пользователей, и этот вариант использования:
- пользователь-викторина-хостер и пользователи-участники находятся на "странице ожидания" до начала теста
- пользователь-викторина-хостер нажимает кнопку "начало теста", чтобы начать тест
- это немедленно вынуждает всех участников-участников быть перенаправленными на новую страницу с вопросом викторины
Я следовал учебному пособию и настроил ActionCable в своем приложении, но я хотел бы знать, как выполнить шаг 3. Мой текущий файл coffeescript для моего канала выглядит так:
# \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
if current_student
# HERE I want to render the page "quiz_question.html.erb"
# ...and then I want to append the answer buttons:
$('answer-buttons').append(data.partial)
send_data: ->
@perform 'send_data'
Я почти уверен, что ответ очень прост, но я прогуглил много учебников по Coffeescript и ActionCable, и почти все они отображают только частички страницы, на которой уже находится пользователь. Я новичок в Rails и ничего не знаю о Coffeescript, поэтому любая помощь будет принята с благодарностью!
РЕДАКТИРОВАТЬ:
Вот как выглядит мой файл coffeescript после попытки следовать ответу Laiths:
App.quiz_data = App.cable.subscriptions.create "QuizDataChannel",
connected: ->
# Called when the subscription is ready for use on the server
$('#btn btn-primary btn-lg').on 'click', (e) -> App.quiz_data.send_data()
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
if current_student
pageHtml = data.page_html
answerHtml = data.answer_html
# This will replace your body with the page html string:
$('body').html(pageHtml)
# Then add your answer buttons:
#$('#answer-buttons').html(answerHtml)
$('answer-buttons').append(answerHtml)
send_data: ->
@perform 'send_data'
И это работа, которую я создал, чтобы передать свои частички и передать их:
# app\assets\jobs\quiz_data_broadcast_job.rb:
class QuizDataBroadcastJob < ApplicationJob
queue_as :default
def perform(answers)
ActionCable.server.broadcast('quiz_data', {
page_html: render_page,
answer_html: render_answer_options(answers)
})
end
private
def render_page
ApplicationController.render(
partial: 'pages/student/quiz_question',
locals: {}
)
end
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
РЕДАКТИРОВАТЬ 2:
Вот что говорит моя консоль Javascript:
Uncaught ReferenceError: App is not defined
at quiz_data.self-21fd077347e9c34e83bab1a2d43a8db5b083fff7ed4eaa02e5314aa78f1dba8b.js:2
at quiz_data.self-21fd077347e9c34e83bab1a2d43a8db5b083fff7ed4eaa02e5314aa78f1dba8b.js:23
И это то, что показывает мне, когда я нажимаю на него:
1 (function() {
2 App.quiz_data = App.cable.subscriptions.create("QuizDataChannel", {
3 connected: function() {
4 return $('#btn btn-primary btn-lg').on('click', function(e) {
5 return App.quiz_data.send_data();
6 });
7 },
8 disconnected: function() {},
9 received: function(data) {
10 var answerHtml, pageHtml;
11 if (current_student) {
12 pageHtml = data.page_html;
13 answerHtml = data.answer_html;
14 $('body').html(pageHtml);
15 return $('answer-buttons').append(answerHtml);
16 }
17 },
18 send_data: function() {
19 return this.perform('send_data');
20 }
21 });
22
23 }).call(this);
РЕДАКТИРОВАТЬ 3: Это мой 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 = {});
App.cable = ActionCable.createConsumer();
}).call(this);
1 ответ
WebSockets на самом деле не предназначены для перенаправления HTTP. Тем не менее, вы все еще можете дать представление, что страница изменилась с помощью некоторого jQuery.
Поскольку вы будете создавать вопрос и ответы после того, как щелчки хоста начнутся, вы можете отправить их оба в своей трансляции.
Я бы сначала предложил изменить quiz_question.html.erb
файл к частичному: _quiz_question.html.erb
, так что вы можете сгенерировать HTML и добавить его к своему телу. Далее включите answer-buttons
элемент внутри вашего файла _quiz_question, так что вы можете получить его с помощью jquery.
Так что это будет выглядеть примерно так, но это будет зависеть от вашей конкретной реализации:
# First create the question HTML partial (ensure this has the answer-
# buttons element inside it):
question_html = ApplicationController.render(partial:
'quizzes/_quiz_question', locals: {question: @question})
# Next create the answer HTML partial:
answer_html = ApplicationController.render(partial:
'answers/_answe_buttonr', locals: {answer: @answer})
# Broadcast both to your channel:
ActionCable.server.broadcast('QuizDataChannel', {
question_html: question_html
answer_html: answer_html
})
# Finally, handle this using jquery in your coffeescript:
received: (data) ->
questionHtml = data.question_html
answerHtml = data.answer_html
# This will replace your body with the question html string:
$('body').html(questionHtml)
# Then add your answer buttons:
$('#answer-buttons').html(answerHtml)