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

Rails开发MCQ答题应用 存储用户选项比对答案展示结果方案

Rails多选题答题&判分功能实现方案

你现有代码存在3个核心问题:Result表字段命名不符合Rails关联约定、表单嵌套导致提交异常、控制器未实现接收参数+判分+存库逻辑,按以下步骤调整即可完成需求:


第一步:修正基础配置问题

首先处理Result表的字段不规范问题:Rails中belongs_to关联默认会找[关联模型名]_id格式的外键,你当前写的q_id、u_id会直接导致关联报错。

  • 如果你还没执行过CreateResults的迁移,可以直接修改原迁移文件:
class CreateResults < ActiveRecord::Migration[6.1]
  def change
    create_table :results do |t|
      t.text :user_choice
      t.references :question, null: false, foreign_key: true
      t.references :user, null: false, foreign_key: true
      t.boolean :is_correct, default: false # 新增字段存储判题结果,避免后续重复比对
      t.timestamps
    end
  end
end
  • 如果已经执行过原迁移,生成新的修正迁移即可:
rails generate migration FixResultForeignKeys

编辑迁移文件内容:

class FixResultForeignKeys < ActiveRecord::Migration[6.1]
  def change
    rename_column :results, :q_id, :question_id
    rename_column :results, :u_id, :user_id
    add_foreign_key :results, :questions
    add_foreign_key :results, :users
    add_column :results, :is_correct, :boolean, default: false
  end
end

执行迁移完成表结构更新:

rails db:migrate

补全模型关联:

  • 在app/models/question.rb中添加反向关联、封装选项获取逻辑:
class Question < ApplicationRecord
  has_many :results
  # 封装选项获取逻辑,避免视图重复拼数组
  def options
    [option1, option2, option3, option4]
  end

  # 可选:存题时自动清洗选项、答案的首尾空格,避免判题误差
  before_save :strip_text_fields
  private
  def strip_text_fields
    self.question = question.strip
    self.option1 = option1.strip
    self.option2 = option2.strip
    self.option3 = option3.strip
    self.option4 = option4.strip
    self.answer = answer.strip
  end
end
  • 你的Result模型代码不需要大改,保留原有验证和关联即可。

配置路由,修改config/routes.rb:

Rails.application.routes.draw do
  resources :questions, only: [:index, :new, :create]
  resources :results, only: [:create]
  get '/results', to: 'results#index', as: :user_results # 结果展示页路由
end

第二步:修正视图表单错误

你当前视图的核心问题是form_with内部嵌套了button_to,会生成两个重叠的form标签导致提交异常,同时单选框参数命名不规范,后端无法批量接收多题答案。把app/views/questions/index.html.erb替换为以下内容:

<div class="card o-hidden border-0 shadow-lg my-5">
  <div class="card-body">
    <div class="row py-5">
      <div class="p-5 w-100">
        <div class="text-center">
          <h1 class="h4 text-gray-900 mb-4">Multiple-Choice Questions</h1>
        </div>
        <%# 直接用form_with提交到results创建路径,不嵌套button_to %>
        <%= form_with url: results_path, method: :post do |form| %>
          <% @questions.each do |question| %>
            <div id="<%= dom_id(question) %>" class="mb-4">
              <p class="font-weight-bold"><%= question.question %></p>
              <% question.options.each_with_index do |option, idx| %>
                <div class="form-check ml-3">
                  <%# 用answers[question_id]的参数结构,后端可直接拿到{题目id:用户选择}的哈希 %>
                  <%= radio_button_tag "answers[#{question.id}]", option, false, 
                    class: "form-check-input", id: "q_#{question.id}_opt_#{idx}" %>
                  <%= label_tag "q_#{question.id}_opt_#{idx}", option, class: "form-check-label" %>
                </div>
              <% end %>
            </div>
          <% end %>
          <div class="sub mt-4">
            <%= form.submit "提交答案", class: "btn btn-primary" %>
          </div>
        <% end %>
        <div class="para1 mt-3">
          <%= link_to '新建题目', new_question_path, class:"btn btn-primary btn-user" %>
        </div>
      </div>
    </div>
  </div>
</div>

同时补全Questions控制器的index动作,确保能拿到所有题目:

class QuestionsController < ApplicationController
  def index
    @questions = Question.all
  end
  # 你原有的new、create动作保持不变即可
end

第三步:实现控制器判分&存库逻辑

生成Results控制器:

rails generate controller Results

编辑app/controllers/results_controller.rb,实现提交、判分、结果展示逻辑:

class ResultsController < ApplicationController
  # 如果你用devise做用户认证保留这行,自己实现的登录逻辑替换为对应鉴权方法
  before_action :authenticate_user!

  def create
    submitted_answers = params[:answers]
    @results = []
    @score = 0
    @total = submitted_answers.count

    # 用事务保证所有答题记录要么全部存成功,要么全部回滚
    ActiveRecord::Base.transaction do
      submitted_answers.each do |question_id, user_choice|
        question = Question.find(question_id)
        is_correct = user_choice.strip == question.answer
        @score += 1 if is_correct

        result = Result.create!(
          user: current_user, # 没做登录的话临时替换为User.first测试功能
          question: question,
          user_choice: user_choice.strip,
          is_correct: is_correct
        )
        @results << result
      end
    end

    flash[:notice] = "答题完成!你的得分是#{@score}/#{@total}"
    redirect_to user_results_path, results: @results
  rescue ActiveRecord::RecordNotFound, ActiveRecord::RecordInvalid => e
    flash[:alert] = "提交失败:#{e.message}"
    redirect_to questions_path
  end

  def index
    @results = flash[:results] || current_user.results.includes(:question).order(created_at: :desc).limit(10)
    @score = @results.count { |r| r.is_correct }
    @total = @results.count
  end
end

第四步:编写结果展示页

新建app/views/results/index.html.erb,用于展示答题对错反馈:

<div class="card o-hidden border-0 shadow-lg my-5">
  <div class="card-body p-5">
    <div class="text-center mb-4">
      <h1 class="h4 text-gray-900 mb-2">答题结果</h1>
      <p class="lead"><%= flash[:notice] %></p>
    </div>
    <% @results.each do |result| %>
      <div class="mb-4 p-3 border rounded <%= result.is_correct ? 'border-success bg-light' : 'border-danger bg-light' %>">
        <p class="font-weight-bold"><%= result.question.question %></p>
        <p>你的答案:<span class="<%= result.is_correct ? 'text-success' : 'text-danger' %>"><%= result.user_choice %></span></p>
        <% unless result.is_correct %>
          <p class="text-success">正确答案:<%= result.question.answer %></p>
        <% end %>
        <p class="mb-0">判定:<strong><%= result.is_correct ? "正确" : "错误" %></strong></p>
      </div>
    <% end %>
    <div class="mt-4">
      <%= link_to "返回答题页", questions_path, class: "btn btn-primary" %>
    </div>
  </div>
</div>

可选优化项

  • 如果暂时没做用户登录模块,可以先把控制器里的current_user替换为固定测试用户,等登录功能做完再替换回来
  • 可以加参数校验,防止用户漏选题目直接提交
  • 可以新增得分统计表,记录用户每次答题的总分、答题时间,做历史答题记录功能

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 03:09:38