Rails7中使用acts_as_votable gem实现点赞按钮报nil错误求助
排查Rails7中acts_as_votable点赞功能的nil错误及最佳实践
错误原因分析
你遇到的undefined method 'id' for nil:NilClass错误,核心原因是**PostsController#like动作中未实例化@post对象**,导致后续调用@post.voted_for?或@post.liked_by时,nil对象被传递给acts_as_votable内部方法,触发了调用id的错误。
修复步骤
1. 补全控制器的实例化逻辑
修改PostsController的like方法,先通过params[:id]找到对应的帖子:
def like @post = Post.find(params[:id]) # 必须新增这行实例化代码 if current_user.voted_for? @post @post.unliked_by current_user else @post.liked_by current_user end # 适配Rails7 Turbo的响应(可选但推荐) respond_to do |format| format.turbo_stream do render turbo_stream: turbo_stream.replace(@post, partial: 'posts/post', locals: { post: @post }) end format.html { redirect_to @post } end end
2. 处理未登录用户的边界情况
未登录时current_user为nil,直接调用voted_for?也会报错,所以在_like_link.html.erb中增加登录判断:
<% if current_user %> <% vote_text = current_user.voted_for?(post) ? "unlike" : "Like" %> <%= button_to vote_text, like_post_path(post), method: :put, remote: :true, class:'like-post' %> <% else %> <%= link_to "请先登录", new_user_session_path, class: 'like-post' %> <% end %>
acts_as_votable最佳使用方式
1. 确保模型配置正确
确认你的User和Post模型已经添加gem的宏定义:
# app/models/user.rb class User < ApplicationRecord acts_as_voter # 用户作为投票者 end # app/models/post.rb class Post < ApplicationRecord acts_as_votable # 帖子作为被投票对象 end
2. 优化点赞计数性能
避免使用post.get_likes.size(会触发全表查询),改用gem自带的缓存计数功能:
- 在Post模型中启用缓存策略:
acts_as_votable cacheable_strategy: :update
- 视图中替换计数代码:
<%= pluralize(post.cached_votes_total, 'Like') %>
3. 适配Rails7 Turbo无刷新更新
利用Turbo Stream实现点赞后无刷新更新页面元素,替代传统的remote:true:
- 控制器中已经添加了
format.turbo_stream的响应(见修复步骤1) - 确保你的
_post.html.erb有唯一的DOM标识(Turbo需要找到替换目标):
<div id="<%= dom_id(post) %>"> <%= render 'posts/likes', post:@post %> <%= render 'posts/like_link', post:@post %> </div>
4. 增加错误处理
防止无效的帖子ID请求,在PostsController中添加异常捕获:
class PostsController < ApplicationController rescue_from ActiveRecord::RecordNotFound, with: :post_not_found private def post_not_found redirect_to posts_path, alert: "请求的帖子不存在" end end
内容的提问来源于stack exchange,提问作者swaeetpotato
相关产品推荐
相关产品推荐

