You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何从View调用下一个ActiveRecord条目实现无重复题目切换?

解决思路:用Session保存状态 + AJAX无刷新更新

你的核心问题在于HTTP是无状态的——每次点击按钮发起请求时,控制器都会重新生成一个新的实例,之前的shuffled_questions数组根本没法跨请求保留,所以每次都会重新洗牌,自然没法实现"连续取不重复题目"的需求。下面是完整的解决方案,一步步来:

1. 重构控制器:用Session保存洗牌后的题目ID数组

我们把洗牌后的ID数组存在用户的Session里,这样每次请求都能复用同一个数组,保证题目不重复:

class QuestionsController < ApplicationController
  def practice
    # 第一次访问时,初始化会话中的洗牌题目ID数组(如果不存在的话)
    session[:shuffled_question_ids] ||= Question.ids.shuffle
    # 取出数组中的第一个题目作为初始展示
    @question = Question.find(session[:shuffled_question_ids].first)
  end

  # 新增处理下一题的动作,专门响应AJAX请求
  def next_question
    # 从Session数组中移除并取出下一个题目ID(shift取开头/pop取末尾,看你需求)
    next_id = session[:shuffled_question_ids].shift
    
    if next_id
      @question = Question.find(next_id)
      # 只渲染题目局部视图,不需要整页布局
      render partial: 'question', locals: { question: @question }, layout: false
    else
      # 所有题目都做完了,返回提示文本
      render plain: "所有题目都完成啦!点击重新开始再来一遍吧~", layout: false
    end
  end

  # 可选:重置练习(清空Session数组,重新洗牌)
  def reset_practice
    session[:shuffled_question_ids] = nil
    redirect_to practice_questions_path
  end
end

2. 配置路由

在config/routes.rb里添加下一题和重置的路由:

Rails.application.routes.draw do
  get 'questions/practice', to: 'questions#practice'
  get 'questions/next', to: 'questions#next_question'
  get 'questions/reset', to: 'questions#reset_practice'
  # 其他你的路由...
end

3. 提取题目局部视图

把原来展示题目的代码单独抽成局部视图app/views/questions/_question.html.erb,方便AJAX请求后复用:

<div id="question-card">
  <h3><%= question.title %></h3>
  <div class="options">
    <% question.options.each_with_index do |option, idx| %>
      <label>
        <input type="radio" name="answer" value="<%= idx %>">
        <%= option.text %>
      </label>
    <% end %>
  </div>
</div>

4. 修改主视图,添加AJAX按钮

在practice.html.erb里引入局部视图,并用JS绑定按钮的AJAX请求:

<h1>选择题练习</h1>

<!-- 题目容器,用来接收AJAX返回的新题目 -->
<div id="question-container">
  <%= render partial: 'question', locals: { question: @question } %>
</div>

<div class="action-buttons">
  <button id="next-btn">下一题</button>
  <button id="reset-btn">重新开始</button>
</div>

<script>
// 下一题按钮逻辑
document.getElementById('next-btn').addEventListener('click', function() {
  fetch('/questions/next')
    .then(response => response.text())
    .then(html => {
      document.getElementById('question-container').innerHTML = html;
    })
    .catch(err => console.log('加载下一题失败:', err));
});

// 重置按钮逻辑
document.getElementById('reset-btn').addEventListener('click', function() {
  window.location.href = '/questions/reset';
});
</script>

关键细节说明

  • Session的作用:每个用户的Session是独立的,所以多用户练习时不会互相干扰,且刷新页面后会保留当前的练习进度(如果需要刷新后重置,可以调整practice动作的逻辑)。
  • AJAX无刷新:用fetch API发送请求,只更新页面上的题目容器,不用整页刷新,体验更流畅。
  • 边界处理:当Session数组为空时,会返回"完成"提示,避免报错。

内容的提问来源于stack exchange,提问作者Martin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 08:11:01