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

Rails 6 中使用jQuery多位置渲染模型及Kaminari分页重复问题求解

问题根因

你写在首页<script>标签内的render_partial函数会在页面首次加载时完成ERB插值渲染,此时@posts固定为第一页的分页数据,后续点击按钮时不会重新请求后端更新@posts的值,因此永远追加的是第一页内容。放在home.js.erb中可以正常运行,是因为该文件是每次点击分页按钮发起远程请求后,由后端动态渲染返回的,会携带对应页码的@posts数据。
注:你当前控制器的分页逻辑存在逻辑错误,第一条排序的@buffers赋值会被第二条where查询完全覆盖,排序逻辑没有生效,下文方案会同步修正该问题。

可行解决方案

方案1:控制器内直接渲染JS响应,无需新增JS模板文件

直接在控制器的action中定义JS响应逻辑,不需要单独创建.js.erb模板文件:

# app/controllers/page_controller.rb
def home
  if "default" == @tab_id || "PostForYou" == @tab_id
    # 修正逻辑:先筛选一周内帖子,再按热度排序
    @buffers = Post.where("created_at >= ?", 1.week.ago.utc)
                   .sort_by { |post| cal_post_hot_point(post) }
                   .reverse
    @posts = Kaminari.paginate_array(@buffers).page(params[:page]).per(10)
  end

  respond_to do |format|
    format.html # 普通页面请求走HTML响应
    format.js do
      # 直接渲染JS逻辑,无需单独模板文件
      render js: <<~JS
        // 追加新分页的帖子内容
        $("<%=j render @posts %>").appendTo($("#home_infinite_scroll"));
        // 更新分页按钮
        <% if @posts.last_page? %>
          $('#home_pagination').html("<a>End</a>");
        <% else %>
          $('#home_pagination').html("<%=j link_to_next_page(@posts, 'Next', remote: true) %>");
        <% end %>
      JS
    end
  end
end

方案2:通用前端分页逻辑,全场景复用无需单独配置

如果不想让控制器处理JS渲染,可以写一套通用的前端分页逻辑,放在全局JS文件中所有分页场景通用,不需要为每个分页场景新建模板:

  1. 控制器改造,远程请求返回JSON格式的渲染结果:
# app/controllers/page_controller.rb
def home
  if "default" == @tab_id || "PostForYou" == @tab_id
    @buffers = Post.where("created_at >= ?", 1.week.ago.utc)
                   .sort_by { |post| cal_post_hot_point(post) }
                   .reverse
    @posts = Kaminari.paginate_array(@buffers).page(params[:page]).per(10)
  end

  respond_to do |format|
    format.html
    format.json do
      render json: {
        posts_html: render_to_string(@posts, layout: false),
        next_page_link: @posts.last_page? ? nil : link_to_next_page(@posts, 'Next', remote: true, class: 'universal-next-btn')
      }
    end
  end
end
  1. 首页模板改造,删除原有自定义JS逻辑,使用通用类标记:
<% if @posts.present? %>
  <!-- 用通用类标记帖子容器,data属性指定对应分页容器 -->
  <div id="home_infinite_scroll" class="universal-post-container">
    <%= render @posts %>
  </div>
  <!-- 用通用类标记分页容器 -->
  <div class="home_pagination_button universal-pagination" data-post-container="#home_infinite_scroll">
    <%= link_to_next_page(@posts, 'Next', remote: true, class: 'universal-next-btn') %>
  </div>
<% end %>
  1. 全局JS(如application.js)中添加通用分页逻辑,所有场景复用:
$(document).on('click', '.universal-next-btn', function(e) {
  e.preventDefault();
  const $btn = $(this);
  const $pagination = $btn.closest('.universal-pagination');
  const $postContainer = $($pagination.data('post-container'));

  $.get($btn.attr('href'), { format: 'json' }, function(res) {
    // 追加新帖子
    $postContainer.append(res.posts_html);
    // 更新分页按钮
    if (res.next_page_link) {
      $pagination.html(res.next_page_link);
    } else {
      $pagination.html("<a>End</a>");
    }
  });
});

该方案的优势是逻辑只需写一次,后续其他模型的分页场景只需添加对应的通用类标记即可使用,无需新增任何JS模板或自定义逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.12 17:33:04