Ruby on Rails form_with未显示校验错误,服务端已捕获问题
注册表单错误信息无法渲染的解决方法
问题背景
服务端能正确捕获用户注册时的校验错误(控制台已打印错误信息),但错误无法在表单上方的视图中渲染展示。合法数据可正常创建用户,非法数据不会创建用户,但错误信息不显示。
相关代码
controllers/registrations_controller.rb
class RegistrationsController < ApplicationController def new @user = User.new end def create @user = User.new(user_params) if @user.save redirect_to root_path, notice: "Successfully signed up!" else puts 'ERRORS BELOW:' puts @user.errors.full_messages render :new end end private def user_params params.require(:user).permit(:email, :password, :password_confirmation) end end
views/registrations/new.html.erb
<%= form_with model: @user, url: signup_path do |f| %> <% if @user.errors.any? %> <div class="alert alert-danger"> <% @user.errors.full_messages.each do |message| %> <div><%= message %></div> <% end %> </div> <% end %> <div class='mb-3'> <%= f.label :email %> <%= f.text_field :email, class:'form-control', placeholder: 'john@test.com' %> </div> <div class='mb-3'> <%= f.label :password %> <%= f.password_field :password, class:'form-control', placeholder: 'password' %> </div> <div class='mb-3'> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class:'form-control', placeholder: 'password' %> </div> <div class="mb-3"> <%= f.submit 'Get Started', class: 'btn btn-primary' %> </div> <% end %>
routes.rb
Rails.application.routes.draw do root to:'main#index' get "signup", to: 'registrations#new' post "signup", to: 'registrations#create' get "about-us", to: 'about#index', as: :about end
控制台输出
Started POST "/signup" for 127.0.0.1 at 2023-01-26 10:18:51 -0600 Processing by RegistrationsController#create as TURBO_STREAM Parameters: {"authenticity_token"=>"[FILTERED]", "user"=>{"email"=>"asdfasdg", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]"}, "commit"=>"Get Started"} ERRORS BELOW: Password confirmation doesn't match Password Email Must be a valid email address Rendering layout layouts/application.html.erb Rendering registrations/new.html.erb within layouts/application Rendered registrations/new.html.erb within layouts/application (Duration: 3.8ms | Allocations: 2734) Rendered shared/_navbar.html.erb (Duration: 0.2ms | Allocations: 134) Rendered shared/_flash.html.erb (Duration: 0.1ms | Allocations: 33) Rendered layout layouts/application.html.erb (Duration: 54.5ms | Allocations: 17541) Completed 200 OK in 423ms (Views: 56.7ms | ActiveRecord: 1.1ms | Allocations: 22605)
问题原因
从控制台的Processing by RegistrationsController#create as TURBO_STREAM可以看出,项目使用了Rails 7默认集成的Turbo。当表单提交失败后直接render :new返回HTML,Turbo会忽略这个响应(因为它期望接收Turbo Stream格式的更新指令),导致页面不会重新渲染,错误信息也就无法显示。
解决方法
方法1:禁用Turbo(快速解决)
修改表单,添加data: { turbo: false }属性,让表单以传统HTTP方式提交:
<%= form_with model: @user, url: signup_path, data: { turbo: false } do |f| %> <!-- 原有表单内容保持不变 --> <% end %>
提交失败后,服务端返回的HTML会直接替换整个页面,错误信息就能正常渲染。
方法2:适配Turbo流(推荐,保持无刷新体验)
如果想保留Turbo的无刷新特性,可以通过Turbo Stream来更新页面中的表单区域:
- 创建Turbo Stream响应模板
在app/views/registrations目录下新建create.turbo_stream.erb:
<%= turbo_stream.replace 'registration-form' do %> <%= render 'form', user: @user %> <% end %>
- 重构表单为局部模板
新建app/views/registrations/_form.html.erb,将原表单内容移进去:
<%= form_with model: user, url: signup_path do |f| %> <% if user.errors.any? %> <div class="alert alert-danger"> <% user.errors.full_messages.each do |message| %> <div><%= message %></div> <% end %> </div> <% end %> <div class='mb-3'> <%= f.label :email %> <%= f.text_field :email, class:'form-control', placeholder: 'john@test.com' %> </div> <div class='mb-3'> <%= f.label :password %> <%= f.password_field :password, class:'form-control', placeholder: 'password' %> </div> <div class='mb-3'> <%= f.label :password_confirmation %> <%= f.password_field :password_confirmation, class:'form-control', placeholder: 'password' %> </div> <div class="mb-3"> <%= f.submit 'Get Started', class: 'btn btn-primary' %> </div> <% end %>
- 修改new.html.erb渲染局部模板
给表单容器添加唯一ID,用于Turbo定位更新:
<div id="registration-form"> <%= render 'form', user: @user %> </div>
这样当注册失败时,服务端会返回Turbo Stream指令,页面中registration-form区域会被替换为带错误信息的表单,实现无刷新更新错误提示。
内容的提问来源于stack exchange,提问作者Moss
相关产品推荐
相关产品推荐

