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

Jquery Ajax注入HTML报错“rails-ujs已加载”的解决过程

解决Rails Ajax注入HTML时"Uncaught Error: rails-ujs has already been loaded!"错误

我完全懂你遇到的这个坑!之前我也踩过一模一样的——你通过Ajax拿到的是完整的HTML页面(包含整个<head>和<script>标签),而你的主页面早就加载并初始化过rails-ujs了,当你把整个页面塞进DOM时,重复的application.js脚本会再次执行,直接触发这个重复加载的错误。

问题根源拆解

你请求/qip_changes/4返回的是完整页面:

<!DOCTYPE html>
<html>
<head>
  <!-- 包含了application.js,里面有rails-ujs -->
  <script src="/assets/application.self-...js" data-turbolinks-track="reload"></script>
</head>
<body>
  <div id='qip_change_show'>...</div>
</body>
</html>

当你用$("#modal_dialog").html(data)把整个页面注入时,浏览器会解析并执行里面的<script>,而rails-ujs在初始化时会检查是否已经加载过,一旦发现重复就抛出错误。

两种可行的解决方案

方案1:为Ajax请求创建专用的无头部Layout(推荐)

这也是你最终用的方法,是最优雅的解决方式:

  1. 在app/views/layouts/下新建一个极简的Layout,比如ajax.html.erb,内容只保留渲染视图的入口:
<%= yield %>
  1. 在你的控制器方法里,判断如果是Ajax请求,就使用这个Layout:
def show
  @qip_change = QipChange.find(params[:id])
  
  # 根据请求类型切换Layout
  if request.xhr?
    render layout: 'ajax'
  end
end

这样Ajax请求返回的就只有你需要的#qip_change_show部分内容,完全不会包含重复的脚本和头部,注入时自然不会报错。

方案2:前端提取目标内容(临时hack方案)

如果暂时不想修改后端Layout,也可以在前端从返回的完整HTML中提取你需要的片段:

$.ajax({ 
  url: "/qip_changes/4", 
  success: function(data){ 
    // 把返回的HTML转为DOM对象,筛选出目标元素的内容
    var desiredContent = $(data).find('#qip_change_show').contents();
    $("#modal_dialog").empty().append(desiredContent);
  } 
});

不过这个方法不推荐长期用——毕竟还是会加载整个页面的资源,而且如果返回的HTML里有其他脚本,还是可能触发意外问题。

总结

核心原则就是:Ajax请求只返回需要的内容片段,不要返回完整页面,避免重复加载主页面已经初始化过的Rails相关脚本(比如rails-ujs、Turbolinks)。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:42:10