【问题标题】:Rails How to use ActionCable to render whole new page on "received:"Rails 如何使用 ActionCable 在“received:”上呈现整个新页面
【发布时间】:2017-10-26 17:11:15
【问题描述】:

我正在尝试使用 2 种用户类型和这个用例制作一个测验应用程序(非单页应用程序):

  1. 测验主持人用户和参与者用户正在“等待 page",直到测验开始
  2. 测验主持人用户单击“测验开始”按钮开始测验
  3. 这会立即强制所有参与者用户重定向到带有测验问题的新页面

我按照教程在我的应用中设置了 ActionCable,但我想知道如何实现第 3 步。我当前频道的咖啡脚本文件如下所示:

# \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'

我很确定答案很简单,但是我在 Google 上搜索了很多 Coffeescript 和 ActionCable 教程,几乎所有这些教程都只将部分内容渲染到用户已经在的页面上。我是 Rails 初学者,对 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);

【问题讨论】:

  • 主持人点击开始按钮后,您是否同时创建问题页面和回答按钮?
  • 是的,这就是@Laith 的计划

标签: ruby-on-rails coffeescript actioncable


【解决方案1】:

WebSockets 并不是真正为执行 HTTP 重定向而设计的。但是,您仍然可以通过一些 jQuery 给出页面发生变化的感觉。

由于您将在主持人单击开始后创建问题和答案,因此您可以将它们都发送到您的广播中。

我首先建议将quiz_question.html.erb 文件更改为部分:_quiz_question.html.erb,以便您可以生成 HTML 并将其附加到您的正文中。接下来,在您的 _quiz_question 文件中包含 answer-buttons 元素,以便您可以使用 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)

【讨论】:

  • 感谢@Laith 的详细建议。我已将第一部分(为我的项目定制)集成到我的咖啡脚本文件的 connected 方法中,第二部分集成到 received 方法中。但现在我收到“未捕获的 ReferenceError:App 未定义” - 在您对我的 previous question 提供帮助后,我已经删除了从我的 Ruby 代码中调用 App 的任何尝试,所以我有点困惑。
  • 你是在你的 javascript 控制台还是服务器日志中得到这个?
  • Javascript 控制台@Laith
  • 这是您应该致电App 的正确位置。 (在你的咖啡脚本中,它被转换为 javascript)。如果你点击它,它会告诉你错误在哪里吗?
  • 似乎cable.js 文件由于某种原因没有运行。该文件是否在您的项目中,是否包含以下内容:(function() { this.App || (this.App = {}); App.cable = ActionCable.createConsumer(); }).call(this);?
猜你喜欢
  • 2022-08-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-01
  • 2014-04-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多