Rails 5.1.6:如何用rails-ujs和jQuery渲染表单验证错误信息
问题分析与解决方案
让我帮你梳理下代码里的问题,以及对应的修复方案:
1. JSON响应与JS代码不匹配
你的控制器在验证失败时,返回的是@lot.errors.full_messages——这是一个纯字符串数组(比如["Price can't be blank", "Lot image can't be blank"]),但你的JS代码里却尝试访问xhr.responseJSON.error,这里根本不存在error这个键,直接取数组本身就对了。
2. 错误容器未初始化
视图里只有<div id="errors"></div>,但你直接往$('#errors ul')里添加<li>,初始状态下这个<ul>是不存在的,所以代码根本不会生效。
3. 数组遍历方式错误
因为返回的是数组,不是键值对对象,用for (message in errors)这种遍历对象的方式是错的,应该用数组的forEach方法。
4. 多余的CSRF Token代码
Rails 5.1+的form_with会自动生成CSRF Token,你手动添加的那个hidden input完全是多余的,可以删掉。
修复方案(两种可选)
方案一:修正全局ajax:error处理逻辑
修改你的application.js代码:
//= require jquery //= require rails-ujs //= require turbolinks //= require bootstrap-sprockets //= require bootstrap //= require_tree . $(document).on("ajax:error", "#new_lot", function(event) { var detail = event.detail; var xhr = detail[2]; // 清空之前的错误信息 const $errorsContainer = $('#errors'); $errorsContainer.empty(); // 创建错误列表容器 const $errorsList = $('<ul class="text-danger"></ul>'); $errorsContainer.append($errorsList); // 遍历错误数组并添加到页面 xhr.responseJSON.forEach(function(errorMsg) { $errorsList.append(`<li>${errorMsg}</li>`); }); });
方案二:用Rails的JS模板处理错误(更符合Rails风格)
这种方式不需要全局的ajax:error监听,直接在控制器里添加format.js分支,用ERB模板渲染错误:
- 修正
lots_controller.rb的create方法:
def create @lot = current_user.lots.build(lot_params) # 这里建议用build+save,而不是create(create会直接保存) respond_to do |format| if @lot.save format.html { redirect_to @lot, notice: 'Lot was successfully created.' } format.json { render :show, status: :created, location: @lot } format.js else format.json { render json: @lot.errors.full_messages, status: :unprocessable_entity } format.js # 会自动渲染对应JS模板 end end end
- 在
app/views/lots目录下创建两个JS模板:
create.js.erb(保持你原来的成功逻辑,顺便清空错误):
$('#new_lot').remove(); $('#new_lot_link').show(); $('#lots').prepend('<%= j render(@lot) %>'); // 清空错误信息 $('#errors').empty();
create.error.js.erb(处理失败场景):
// 清空之前的错误信息 const $errorsContainer = $('#errors'); $errorsContainer.empty(); // 创建错误列表并添加内容 const $errorsList = $('<ul class="text-danger"></ul>'); <% @lot.errors.full_messages.each do |msg| %> $errorsList.append('<li><%= j msg %></li>'); <% end %> $errorsContainer.append($errorsList);
- 最后移除
_form.html.erb里多余的CSRF Token代码:
删掉这一行:
<%= tag(:input, :type => "hidden", :name => request_forgery_protection_token.to_s, :value => form_authenticity_token) %>
内容的提问来源于stack exchange,提问作者anndrew78
相关产品推荐
相关产品推荐

