多态模型下在局部表单中显示验证错误的问题
问题分析与解决方案
核心问题梳理
- 错误保存对象:
CommentsController#create里调用了@commentable.save,但实际要保存的是评论实例@comment,验证错误只会出现在@comment上,和@commentable无关。 - 错误对象传递错误:表单里把
@commentable.errors传给错误提示组件,但错误实际属于@comment。 - 重定向丢失实例:验证失败时用
redirect_to会发起新请求,带错误的@comment实例会被销毁,页面拿不到错误数据,应该用render保留实例。 - 缺少参数白名单:
CommentsController未定义comment_params,导致参数无法通过,同时无法触发正常验证。 - 表单实例错误:表单直接用
Comment.new,验证失败时应该用带错误的@comment实例,才能回显用户输入和错误信息。
修正后的代码
1. controllers/comments_controller.rb
class CommentsController < ApplicationController # GET /comments/new def new @comment = @commentable.comments.new end # POST /comments or /comments.json def create @comment = @commentable.comments.new(comment_params) @comment.profile = current_user.profile respond_to do |format| if @comment.save # 改为保存评论实例@comment format.html { redirect_to @commentable, notice: "Comment was successfully created." } else # 渲染原页面,保留带错误的@comment实例 format.html { render "/#{@commentable.class.name.downcase.pluralize}/show", status: :unprocessable_entity } end end end private def set_comment @comment = Comment.find(params[:id]) end # 添加参数白名单,允许body字段 def comment_params params.require(:comment).permit(:body) end end
2. views/comments/_form.html.erb
<%# 接收局部变量comment,优先使用传入的实例,否则新建 %> <%= form_with(model: [commentable, comment || Comment.new], class: "contents") do |form| %> <%# 传递评论实例的错误信息 %> <%= render "/shared/error_messages", errors: comment&.errors || [], title: "Comment creation failed" %> <%= form.label :body, "Comment" %> <%= form.text_area :body, class: "w-full" %> <div class="inline"> <%= form.submit class: "btn-primary" %> </div> <% end %>
3. views/posts/show.html.erb
<%= render "/shared/navbar" %> <div class="container"> <%= render @post %> <h3>COMMENTS</h3> <%# 传递@comment实例,验证失败时会存在 %> <%= render partial: "comments/form", locals: { commentable: @post, comment: @comment } %> <%= render @post.comments %> </div>
额外说明
- 验证失败时,
render "/posts/show"会直接渲染详情页,@comment实例被保留,表单能获取错误信息并回显用户输入。 - 确保
Comment模型已添加验证规则,比如validates :body, presence: true,否则不会触发错误提示。
内容的提问来源于stack exchange,提问作者bitsmyth
相关产品推荐
相关产品推荐

