Rails测验应用question_id未随用户答题选择正确更新问题
问题说明
开发Rails测验应用时,提交答题结果后question_id字段始终存储为最后一道题的ID(当前场景为11),无法匹配用户实际作答的题目ID,其余user_choice、user_id字段存储正常。
现有代码结构
- 三个核心模型:
question.rb、user.rb、result.rb
Question模型代码
class Question < ApplicationRecord validates :question, presence: true validates :option1, presence: true validates :option2, presence: true validates :option3, presence: true validates :option4, presence: true validates :answer, presence: true end
Question表迁移文件
class CreateQuestions < ActiveRecord::Migration[6.1] def change create_table :questions do |t| t.text :question t.text :option1 t.text :option2 t.text :option3 t.text :option4 t.text :answer t.timestamps end end end
Result表迁移文件
class CreateResults < ActiveRecord::Migration[6.1] def change create_table :results do |t| t.text :user_choice # 实际包含question_id、user_id两个外键 t.timestamps end end end
Result控制器代码
class ResultController < ApplicationController def create @result=Result.create( user_choice: params[:user_choice], question_id: params[:question_id], user_id: current_user.id ) end end
答题页视图(view/question/index)代码
<div class="card o-hidden border-0 shadow-lg my-5"> <div class="card-body "> <!-- Nested Row within Card Body --> <div class="row py-5"> <div class="p-5"> <div class="text-center"> <h1 class="h4 text-gray-900 mb-4 ">Multiple-Choice Questions</h1> </div> <%= form_with model: @result ,url: result_path do |f| %> <% @questions.each do |question| %> <div> <%= f.hidden_field :question_id, value: question.id %> <%= f.hidden_field :user_id, value: current_user.id %> <p><%= question.question %></p> <% choices = [question.option1, question.option2, question.option3, question.option4] %> <% choices.each do |c| %> <div> <%= f.radio_button :"user_choice[#{question.id}]", c %> <%= f.label :user_choice, c %> </div> <% end %> </div> <% end %> <div class="sub"> <%= f.submit "Submit", class:"btn btn-primary" %></div> <% end %> <div class="para1"><%= link_to 'New Question', new_question_path,class:"btn btn-primary btn-user" %> </div> </div> </div> </div> </div> </div> </div>
问题根因
- 你在
@questions.each循环中重复渲染了name属性相同的question_id隐藏输入框。HTML表单提交同名参数时,只会保留最后一个输入项的值,因此后端拿到的params[:question_id]永远是循环到最后一道题的ID。 - 你当前的单选框命名为
user_choice[#{question.id}],提交后params[:user_choice]本身就是以题目ID为键、用户选择的选项为值的哈希结构,原有控制器单次创建一条Result记录的逻辑,本身也不匹配一次提交多道题答案的业务场景。 - 之前
user_id能正常存储,是因为循环里所有隐藏域的user_id值都是当前用户ID,哪怕取最后一个值也不会出错,但这种把用户ID放在前端传参的方式有被篡改的风险,不推荐使用。
修复方案
第一步:修正视图层代码
删掉循环里重复的question_id、user_id隐藏域,同时修正单选框label的绑定关系(原有label点击无法选中对应单选框),修正后的表单部分代码:
<%= form_with model: @result ,url: result_path do |f| %> <% @questions.each do |question| %> <div> <p><%= question.question %></p> <% choices = [question.option1, question.option2, question.option3, question.option4] %> <% choices.each do |c| %> <div> <%= f.radio_button :"user_choice[#{question.id}]", c %> <%= f.label :"user_choice[#{question.id}]", c %> </div> <% end %> </div> <% end %> <div class="sub"> <%= f.submit "Submit", class:"btn btn-primary" %></div> <% end %>
第二步:修正控制器create逻辑
遍历params[:user_choice]哈希,为每道题的作答单独创建Result记录,直接从哈希key取题目ID,user_id直接从后端current_user取,完全不依赖前端传参:
class ResultController < ApplicationController def create # 遍历所有题的作答,逐题存储结果 params[:user_choice].each do |question_id, selected_choice| Result.create( user_choice: selected_choice, question_id: question_id, user_id: current_user.id ) end # 按需添加跳转、提示逻辑 redirect_to results_path, notice: "答题提交成功" end end
额外优化建议
在Result模型里补全关联和参数校验,避免脏数据:
# result.rb class Result < ApplicationRecord belongs_to :user belongs_to :question validates :user_choice, presence: true end
同时在Question、User模型中补全反向关联:
# question.rb has_many :results # user.rb has_many :results
内容的提问来源于stack exchange,提问作者Abu Bakar
相关产品推荐
相关产品推荐

