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

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自带的缓存计数功能:

  1. 在Post模型中启用缓存策略:
acts_as_votable cacheable_strategy: :update
  1. 视图中替换计数代码:
<%= 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.23 19:12:42