以随机顺序将每条记录显示为新页面

时间:2015-02-17 09:52:04

标签: ruby-on-rails ruby psql

我花了两天的时间试图弄清楚如何解决这个问题,但似乎无法找到解决方案,所以希望别人可以帮助我。

我正在制作一个有测试的基本应用。每个测试都包含几个问题。我试图做到这一点,当用户选择完成一个测试时,他们会在新页面上随机给出每个问题(他们必须选择一个答案继续下一个问题等)。

我有什么办法可以在rails中使用.each循环吗?

在我目前的test_controller.rb中,我有:

def show
    @test = Test.find(params[:id])
    @questions = Question.all
    @question = @questions.sample(5)
end

在我的questions_controller.rb中,我有:

def show
    @test = Test.find(params[:test_id])
    @questions = Question.all
    @question = @questions.sample(5)
    # @question = Question.find(params[:id])
  #   @test = Test.find(params[:test_id])
  end

  def edit
    @test.questions.find(params[:id])
  end

  def update
    @question = Question.find(params[:id])
    @question.update(params.require(:question).permit(:answer))
  end

在我的问题/ show.html.erb中我有:

<% @question.each do |question| %>
    <h2>Question </h2>
    <p>
      <%= image_tag question.image.url(:medium) %>
    </p>
    <%= form_tag edit_test_question_path do %>
      <%= radio_button_tag :answer, "a" %> a
      <%= radio_button_tag :answer, "b" %> b
      <%= radio_button_tag :answer, "c" %> c
      <%= radio_button_tag :answer, "d" %> d
      <br/>
      <%= submit_tag 'Save', class: "btn btn-lg btn-success" %>
    <% end %>
  <% end %>

但是当我使用它时,它目前在一个页面上显示所有5个问题,这意味着网址是:

http://localhost:3000/tests/2/questions/1%2F5%2F3%2F4%2F2

这显然意味着form_tag不起作用,因为它正在尝试转到http://localhost:3000/tests/2/questions/1%2F5%2F3%2F4%2F2/edit,而这种情况并不存在。

有没有办法让它一次只显示一个问题并以随机顺序循环遍历所有问题?我需要能够在用户继续之前保存用户对问题的回答。

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:0)

我认为您应该创建名为TestSession的实体,当用户进入测试会话时,使用QuestionID和空答案ID在数据库上创建记录集。当用户单击下一步时,您将使用用户的答案更新当前记录。此流程将为您提供定义下一个问题的灵活性。 假设我们的test_sessions表中有5条记录,可能看起来像

id | user_id | question_id | answer | currently_shown

所以在您的控制器中,您可以检索下一个问题

@next_question = @test_session.where(:answer => nil).sample

这将保证从未回答的收集中随机提出问题

PS:更新

为了防止用户更新并获得新问题,您可以添加1个字段,并在收到下一个随机问题后填入true。并借助过滤器验证是否应显示当前问题。这可能看起来很复杂,但一旦你理解了整个模式,就会很容易。 在用户回答问题

之后也不要忘记制作currently_shown= false

答案 1 :(得分:0)

您不能使用each,因为每个页面都会向服务器发出新请求,并且每个循环都必须在您提供响应之前完成。

我建议使用wicked gem来实现此目的,并通过一些小调整来随机化步骤。

邪恶的方式是你在一个控制器中拥有所有逻辑。通常,新操作负责通过将其ID存储在会话中来设置要处理的模型。我们会做类似的事情,但我们会随机选择一些问题并将这些ID存储在会话中。第二步是强制wicked在会话中使用此数组而不是硬编码步骤。

所以你的控制器看起来像是:

class MyTest < ApplicationController

  include Wicked::Wizard
  before_action :set_steps, only: [:show, :update]
  before_action :setup_wizard, only: [:show, :update]

  def new
    # Generate list of questions and store them in a session
    session[:question] = Question.order('RAND()').limit(5).pluck(:id)
    redirect_to action: :show
  end

  def show
    @question = Question.find(step)
    # No render_wizard here as we are using same template for all steps
  end

  def update
    @question = Question.find(params[:id])
    @question.update(params.require(:question).permit(:answer))
    redirect_to next_wizard_step # you can add validations here as well
  end

  private

  def set_steps
    self.steps = session[:questions]
  end

  def finish_wizard_path
     test_results_path # where to go hen all questions has been answered
  end

当然这只是顶级视图,你可以在这里添加更多逻辑,包括最后的测试总结等。

使用此功能可确保用户在从数据库中挑选出一组问题后无法更改这些问题。问题的ID将显示在网址中,但是用户无法更改它,因为他将获得步骤未定义的错误。如果您更喜欢显示1,2,3,4,5,这也很容易实现 - 在会话中保留问题,但不要使用该数组来定义步骤。将通常的邪恶方式定义为1,2,3,4,5,并在展示和更新中使用find(session[:questions][step.to_i - 1]) - 可能性是无穷无尽的。

另请注意,有了这个逻辑,您可以让用户在问题之间跳转来纠正他之前的答案,这非常简洁。