Ruby on Rails实现鼠标悬停写入数据库及元素移除问题
看起来你遇到了两个核心问题:一是客户端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é

