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

Ruby on Rails实现鼠标悬停写入数据库及元素移除问题

解决Rails中hover事件触发数据库更新及article.id获取问题

看起来你遇到了两个核心问题:一是客户端JS无法获取每个文章对应的正确article.id,二是没法成功触发Rails的数据库写入请求。我来一步步帮你搞定:

1. 先搞定正确获取每个文章的ID问题

你现在在JS里写<%= article.id %>是行不通的——因为ERB是服务器端渲染的,当页面加载时这个代码只会渲染当前循环中最后一个(或者第一个,取决于你的循环逻辑)article的ID,所有.newness元素的JS逻辑都会复用这个固定值。

解决办法是把每个文章的ID存在DOM元素的data-*属性里,这样客户端JS就能拿到对应元素的专属ID:

<!-- 修改你的HTML部分,给.newness添加data属性 -->
<h5>
<%= article.title %>
</h5>
<div class="newness" data-article-id="<%= article.id %>">new</div>

然后在JS里通过$(this).data('article-id')就能拿到当前hover元素对应的文章ID了:

$('.newness').hover(
  function() {
    const $this = $(this);
    // 先判断是否已经处理过,避免重复请求
    if ($this.hasClass('processed')) return;
    
    $this.addClass('hover processed');
    const articleId = $this.data('article-id');
    console.log('当前文章ID:', articleId); // 这里可以先打印验证是否正确
    // 接下来就是发送请求到Rails后端
  }
);

2. 实现Rails后端的数据库写入

首先你需要有对应的路由和控制器动作来处理这个浏览记录的创建:

第一步:添加路由

在config/routes.rb里添加一条POST路由:

post '/user_articles', to: 'user_articles#create', as: 'user_articles'

第二步:实现控制器动作

假设你已经有UserArticlesController,在里面添加create方法:

class UserArticlesController < ApplicationController
  def create
    # 确保用户已登录,根据你的认证方式调整,比如devise的current_user
    if current_user
      # 避免重复创建记录,用find_or_create_by
      UserArticle.find_or_create_by(user_id: current_user.id, article_id: params[:article_id])
      head :ok # 返回成功状态码,不需要返回内容
    else
      head :unauthorized # 未登录的情况返回401
    end
  end
end

第三步:在JS里发送AJAX请求

Rails推荐使用UJS(Unobtrusive JavaScript)来处理AJAX请求,也可以用原生的fetch或者jQuery的$.ajax。这里用jQuery的方式更贴合你的现有代码:

$('.newness').hover(
  function() {
    const $this = $(this);
    if ($this.hasClass('processed')) return;
    
    $this.addClass('hover processed').hide(); // 直接隐藏new标签,或者按你的样式处理
    
    const articleId = $this.data('article-id');
    // 发送POST请求到后端
    $.ajax({
      url: '/user_articles', // 或者用Rails的路由辅助方法:'<%= user_articles_path %>'
      method: 'POST',
      data: { article_id: articleId },
      headers: {
        'X-CSRF-Token': $('meta[name="csrf-token"]').attr('content') // 必须带上CSRF令牌,否则Rails会拒绝请求
      },
      success: function() {
        console.log('浏览记录已保存');
      },
      error: function(xhr) {
        console.error('保存失败:', xhr.responseText);
        // 可以在这里做错误处理,比如恢复new标签
        $this.removeClass('processed').show();
      }
    });
  }
);

注意:如果你的JS代码是在单独的.js文件里(而不是ERB模板中),那么<%= user_articles_path %>这种ERB语法是无法解析的,这时候要么把JS代码放在ERB模板里,要么把路由地址存在页面的meta标签里,或者直接写完整的路由路径。

3. 额外优化点

  • 避免重复请求:我们给元素加了processed类,这样用户多次hover同一个元素时不会重复发送请求。
  • CSRF保护:Rails默认开启CSRF保护,所以AJAX请求必须带上X-CSRF-Token,这个令牌可以从页面的<meta name="csrf-token" content="...">标签里获取。
  • 处理未登录用户:控制器里判断了current_user,如果用户未登录,返回401状态,JS里可以根据这个做相应的提示。

这样修改后,你应该就能正确获取每个文章的ID,并且成功触发数据库写入了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:43:53