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); });
后端配置:
- 在
routes.rb添加批量路由:
resources :user_activities do post 'batch', on: :collection end
- 在
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
相关产品推荐
相关产品推荐

