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(推荐)
这也是你最终用的方法,是最优雅的解决方式:
- 在
app/views/layouts/下新建一个极简的Layout,比如ajax.html.erb,内容只保留渲染视图的入口:
<%= yield %>
- 在你的控制器方法里,判断如果是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
相关产品推荐
相关产品推荐

