如何为Rails测验应用的Replies控制器Create动作实现30分钟超时处理?
嘿,针对你这个测验应用的定时需求,我整理了几个实用的实现思路,结合Rails后端和前端来搞定:
方案一:前端定时自动触发Create动作(适合需要自动提交的场景)
如果允许自动提交(哪怕是空参数),可以通过前端定时器在30分钟后模拟表单提交或直接发送请求到Create接口:
步骤1:在测验页面添加定时逻辑
在你的测验视图页面(比如quizzes/show.html.erb)里加入JavaScript定时器:document.addEventListener('DOMContentLoaded', function() { // 设置30分钟后执行的定时器(单位:毫秒) setTimeout(function() { // 优先尝试提交现有表单 const quizForm = document.getElementById('quiz-submit-form'); if (quizForm) { quizForm.submit(); } else { // 没有表单的话,用Fetch API直接发送POST请求到replies#create fetch('/replies', { method: 'POST', headers: { 'Content-Type': 'application/json', // 必须带上Rails的CSRF令牌,否则会被拦截 'X-CSRF-Token': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ reply: { answer_ids: [] } // 空参数,需要后端处理 }) }).then(() => { // 提交后重定向到首页或结果页 window.location.href = '/'; }); } }, 30 * 60 * 1000); });步骤2:后端处理空参数的提交
在replies_controller.rb的Create动作里,处理空参数的情况:def create @reply = current_user.replies.build(reply_params) # 如果没有提交任何答案,标记为自动提交状态 if @reply.answer_ids.blank? @reply.status = 'auto_submitted' end if @reply.save redirect_to quiz_results_path, notice: '测验已自动提交' else # 保存失败的话直接重定向首页 redirect_to root_path, alert: '自动提交失败,请稍后重试' end end private def reply_params params.require(:reply).permit(answer_ids: []) end
方案二:前端定时提示/强制重定向(如果不允许空参数提交)
如果空参数提交不可行,那可以在30分钟后给用户提示,或者直接强制重定向到首页:
document.addEventListener('DOMContentLoaded', function() { setTimeout(function() { // 先弹出提示框询问用户 const confirmSubmit = confirm('测验时间已到,请提交答案或返回首页'); if (confirmSubmit) { document.getElementById('quiz-submit-form').submit(); } else { // 用户取消则重定向首页 window.location.href = '/'; } // 也可以直接不提示,强制重定向 // window.location.href = '/'; }, 30 * 60 * 1000); });
关键补充:后端兜底验证(防止前端作弊)
前端定时器很容易被用户通过浏览器控制台篡改或取消,所以一定要在后端加一层时间验证:
步骤1:记录用户开始测验的时间
在进入测验页面的控制器动作里(比如quizzes#show),把开始时间存入session:def show @quiz = Quiz.find(params[:id]) # 记录开始时间到session session[:quiz_start_time] = Time.now end步骤2:在Create动作里校验时间
def create # 取出session里的开始时间,判断是否超过30分钟 start_time = session[:quiz_start_time] if start_time.present? && (Time.now - start_time) > 30.minutes redirect_to root_path, alert: '测验时间已过期,请重新开始' return end # 后续的Create逻辑... end
内容的提问来源于stack exchange,提问作者user3576036
相关产品推荐
相关产品推荐

