Rails分页点击后缺失head标签,CSS/JS未渲染问题求助
问题:Rails视图切换后分页仅渲染局部视图缺失布局
我的Rails应用包含看板视图(kanban view)和经典视图(classic view)两类视图,首次加载经典视图时一切正常。但点击分页(尝试过kaminari和pagy gem)的第2/3页后,页面仅渲染_classic_view.html.erb局部视图,未加载包含所有CSS、JS文件的application.html.erb布局文件,导致浏览器中缺失head标签,页面内容显示异常。
相关代码
index.html.erb
... <div id="partial-container"></div> ... <script> const partialContainer = document.getElementById('partial-container'); const valueFromBrowserData = localStorage.getItem('view'); // 返回 kanban 或 classic if (valueFromBrowserData) { selectDropdown.value = valueFromBrowserData; loadPartial(window.location.pathname, valueFromBrowserData, partialContainer); } form.addEventListener('change', (event) => { const dropdownValue = event.target.value; localStorage.setItem('view', dropdownValue); loadPartial(window.location.pathname, dropdownValue, partialContainer); }); function loadPartial(url, value, container) { loaded_partials = true; // 显示加载器 var loader = document.getElementById('loader-style'); if (loader) { loader.style.display = 'flex'; } // 清空容器 container.innerHTML = ''; const urlWithParams = `${url}?name=${encodeURIComponent(value)}` fetch(urlWithParams) .then((response) => response.text()) .then((partialHtml) => { container.innerHTML = partialHtml; removeEmptyHeaders(); // 隐藏加载器 if (loader) { loader.style.display = 'none'; } }) .catch((error) => { console.error('Error loading partial:', error); // 出错时隐藏加载器 if (loader) { loader.style.display = 'none'; } }); } </script>
_classic_view.html.erb
<div id="flash-notification"></div> <div class="can-table-data"> <% @data.each do |data|%> ... <!-- 展示数据详情 --> <% end %> </div> <div class="table-pagination"> <%= paginate @data %> <div class="dynamic-page-selection mt-1"> <div class="dropdown"> <button class="btn btn-row dropdown-toggle" type="button" data-bs-toggle="dropdown" aria-expanded="false"> <%= @data.limit_value %> Rows / Page </button> <ul class="dropdown-menu"> <% PAGE_SIZES.each do |size| %> <li><%= link_to size, url_for(per_page: size), class: "dropdown-item" %></li> <% end %> </ul> </div> </div> </div>
application.html.erb
<!DOCTYPE html> <html> <head> <title>Test</title> <meta name="viewport" content="width=device-width,initial-scale=1"> <%= csrf_meta_tags %> <%= csp_meta_tag %> <!-- Dropzone Stand alone V6 css --> <link href="https://unpkg.com/dropzone@6.0.0-beta.1/dist/dropzone.css" rel="stylesheet" type="text/css" /> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css"> <%= javascript_include_tag "jquery" %> <%= stylesheet_link_tag "application.bootstrap", "data-turbo-track": "reload" %> <%= javascript_importmap_tags %> <%= javascript_include_tag "delete_confirmation_dialog" %> <%= javascript_include_tag "polling" %> <%= javascript_include_tag 'sortable_developer_fields' %> <script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> </head> <body> <%if @current_user %> <div class="wrapper"> <%= render 'layouts/header' %> <div class="content-page"> <div class="custom-container"> <%= yield %> </div> </div> </div> <% else %> <%= render 'layouts/flash' %> <%= yield %> <% end %> </body> </html>
解决方案
1. 控制器区分AJAX与普通请求
在对应控制器的index动作中,判断请求类型,AJAX请求返回局部视图,普通请求返回完整布局:
def index @data = YourModel.page(params[:page]).per(params[:per_page] || 20) @view = params[:name] || 'classic' if request.xhr? # AJAX请求(fetch发送)仅渲染局部视图 render partial: "_#{@view}_view", layout: false else # 首次加载或整页跳转,渲染完整布局 render end end
2. 拦截分页链接点击,用AJAX加载
在index.html.erb的script中添加事件监听,阻止分页链接的默认跳转,调用loadPartial加载新页面:
// 监听分页及每页条数选择的点击事件 document.addEventListener('click', function(e) { const targetLink = e.target.closest('.pagination a, .dynamic-page-selection a'); if (targetLink) { e.preventDefault(); const currentView = localStorage.getItem('view') || 'classic'; loadPartial(targetLink.href, currentView, partialContainer); } });
3. 修正loadPartial的URL参数处理
原有拼接方式会丢失分页参数,改为保留原有URL参数并添加视图参数:
function loadPartial(url, value, container) { loaded_partials = true; const loader = document.getElementById('loader-style'); if (loader) loader.style.display = 'flex'; container.innerHTML = ''; // 解析URL并添加视图参数 const urlObj = new URL(url); urlObj.searchParams.set('name', encodeURIComponent(value)); fetch(urlObj.toString()) .then(response => response.text()) .then(partialHtml => { container.innerHTML = partialHtml; removeEmptyHeaders(); if (loader) loader.style.display = 'none'; }) .catch(error => { console.error('Error loading partial:', error); if (loader) loader.style.display = 'none'; }); }
4. 验证逻辑
- 首次加载是普通HTTP请求,控制器返回完整布局,页面正常渲染。
- 切换视图或点击分页时,通过AJAX请求获取局部视图,插入到容器中,不会触发整页跳转,保留原有布局的CSS/JS。
内容的提问来源于stack exchange,提问作者hardik
相关产品推荐
相关产品推荐

