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

POST请求触发页面刷新问题求助(附代码及日志)

解决鼠标悬停标记已读时页面刷新及重复请求问题

先拆解你的核心问题:页面刷新是因为后端控制器的create动作执行了重定向(redirect_to),而你的AJAX请求收到这个重定向响应后,浏览器会自动跟随跳转,导致页面回到首页。另外,hover事件会绑定mouseenter和mouseleave两个触发时机,这也是日志里出现两次POST请求、第二次因唯一性约束被回滚的原因。

第一步:修复页面刷新问题

修改你的UserActivitiesController#create方法,针对AJAX请求返回非重定向的响应。AJAX请求不需要页面跳转,只需要告知请求成功/失败即可:

def create
  @user_activity = current_user.user_activities.build(user_activity_params)
  
  if @user_activity.save
    respond_to do |format|
      format.html { redirect_to root_path } # 保留非AJAX请求的跳转逻辑
      format.json { head :ok } # AJAX请求返回成功状态码,无内容
      format.js { head :ok }
    end
  else
    respond_to do |format|
      format.html { redirect_to root_path, alert: 'Failed to mark as read' }
      format.json { head :unprocessable_entity } # 失败返回对应状态码
      format.js { head :unprocessable_entity }
    end
  end
end

第二步:避免hover触发重复请求

hover()方法会同时绑定鼠标进入和离开事件,你只需要在鼠标进入时触发一次请求即可,还可以添加防抖逻辑避免快速滑动鼠标时的误触:

$('.newness').mouseenter(function() {
  const $element = $(this);
  $element.addClass('hover');
  const newnessId = $element.data('id');
  
  // 防抖:取消未执行的请求,避免快速滑动时多次触发
  clearTimeout($element.data('hoverTimeout'));
  const timeout = setTimeout(() => {
    $.ajax({
      url: '/user_activities',
      method: 'POST',
      data: { user_activity: { activity_id: newnessId } },
      dataType: "script",
      success: () => {
        // 可选:添加已读样式反馈
        $element.addClass('marked-as-read');
      }
    });
  }, 300); // 300ms延迟,过滤误触
  
  $element.data('hoverTimeout', timeout);
}).mouseleave(function() {
  // 鼠标离开时取消未执行的请求
  clearTimeout($(this).data('hoverTimeout'));
});

第三步:实现批量请求优化(可选)

如果想减少数据库请求次数,可以收集悬停过的文章ID,定时批量发送:

前端代码:

const pendingReadIds = new Set();
let batchRequestTimeout;

$('.newness').mouseenter(function() {
  const $element = $(this);
  const newnessId = $element.data('id');
  
  // 跳过已标记或待处理的ID
  if ($element.hasClass('marked-as-read') || pendingReadIds.has(newnessId)) return;
  
  pendingReadIds.add(newnessId);
  $element.addClass('pending-read');
  
  // 每500ms批量发送一次请求
  clearTimeout(batchRequestTimeout);
  batchRequestTimeout = setTimeout(() => {
    const ids = Array.from(pendingReadIds);
    pendingReadIds.clear();
    
    $.ajax({
      url: '/user_activities/batch',
      method: 'POST',
      data: { user_activity: { activity_ids: ids } },
      dataType: "script",
      success: () => {
        ids.forEach(id => {
          $(`.newness[data-id="${id}"]`)
            .addClass('marked-as-read')
            .removeClass('pending-read');
        });
      }
    });
  }, 500);
});

后端配置:

  1. 在routes.rb添加批量路由:
resources :user_activities do
  post 'batch', on: :collection
end
  1. 在UserActivitiesController添加批量处理动作:
def batch
  activity_ids = params[:user_activity][:activity_ids]
  # 批量创建,自动跳过已存在的记录(利用唯一性约束)
  activity_ids.each do |id|
    current_user.user_activities.find_or_create_by(activity_id: id)
  end
  
  respond_to do |format|
    format.html { redirect_to root_path }
    format.json { head :ok }
    format.js { head :ok }
  end
end

这样既解决了页面刷新的问题,又优化了请求次数,避免重复提交。

内容的提问来源于stack exchange,提问作者Benjamin Barbère

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 06:47:34