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

Rails嵌套资源创建Question对象失败问题求助

解决Rails嵌套资源创建Question失败的问题

看起来你在嵌套资源的使用上踩了几个常见的坑,我来帮你一步步排查和修复:

1. 路由助手调用错误

在create动作的成功分支里,你用了redirect_to coin_question(@question.coin_id, @question.id),这是不对的——Rails的路由助手方法名应该是coin_question_path(或者coin_question_url,前者用于相对路径),少了_path后缀会导致方法找不到,进而触发错误,最终走else分支渲染new页面。

2. 新建Question时未关联对应的Coin

你的new动作里,@question = current_user.questions.build只是关联了用户,但没有关联当前的@coin。这样一来,即使表单提交,coin_id可能没有被正确赋值(或者依赖用户提交,存在安全风险),导致@question.save失败。

正确的做法是通过@coin来构建关联的Question,这样会自动把coin_id赋值好,不需要在表单里处理:

def new
  @question = @coin.questions.build(user: current_user)
end

def create
  @question = @coin.questions.build(question_params.merge(user: current_user))
  # ... 后续逻辑
end

3. 表单路由可以更简洁(且不易出错)

你手动指定了url: coin_questions_path(@coin.id),其实Rails支持直接用嵌套的对象数组来生成正确的路由,把simple_form_for改成这样:

<%= simple_form_for [@coin, @question] do |f| %>
  <%= f.input :ques_num %>
  <%= f.input :content %>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

这样Rails会自动识别这是嵌套资源的创建路由(POST /coins/:coin_id/questions),比手动写url更可靠。

4. 移除参数里的coin_id(安全优化)

既然我们通过关联构建Question,已经自动赋值了coin_id,就不需要在question_params里允许coin_id参数了——避免恶意用户篡改这个值,把question_params改成:

def question_params
  params.require(:question).permit(:content, :ques_num)
end

修改后的完整代码参考

QuestionsController

class QuestionsController < ApplicationController
  before_action :find_coin
  before_action :find_question, only: [:show]
  before_action :authenticate_user!, except: [:index, :show]

  def index
    @questions = @coin.questions.order("created_at DESC")
  end

  def show
  end

  def new
    @question = @coin.questions.build(user: current_user)
  end

  def create
    @question = @coin.questions.build(question_params.merge(user: current_user))
    if @question.save
      redirect_to coin_question_path(@coin, @question), notice: "Question created successfully!"
    else
      render 'new'
    end
  end

  private

  def find_question
    @question = Question.find(params[:id])
  end

  def find_coin
    @coin = Coin.find(params[:coin_id])
  end

  def question_params
    params.require(:question).permit(:content, :ques_num)
  end
end

new页面表单

<%= simple_form_for [@coin, @question] do |f| %>
  <%# 如果有错误信息,可以在这里显示,方便调试 %>
  <% if @question.errors.any? %>
    <div class="alert alert-danger">
      <ul>
        <% @question.errors.full_messages.each do |msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>

  <%= f.input :ques_num %>
  <%= f.input :content %>
  <%= f.submit "Post", class: "btn btn-primary" %>
<% end %>

另外,建议你保留表单里的错误信息显示,这样保存失败时能直观看到问题原因,方便后续调试。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:47:52