Ruby on Rails类Twitter网站:帖子浏览追踪与views_count报错解决
问题描述
我正在开发类Twitter网站,需要实现帖子浏览追踪功能:
- 统计帖子总浏览量
- 记录浏览者的
user_id,用于活跃用户统计
之前的浏览功能只能统计总浏览量,没法记录用户信息。
现在遇到错误:undefined method 'views_count' for nil:NilClass,报错代码在post.html中:
<h6 class="card-subtitle mb-2 text-secondary"><%= @post.views_count %> zhlédnutí</h6>
我的PostsController代码如下:
class PostsController < ApplicationController before_action :set_post, only: [:edit, :update, :destroy] before_action :authorize_user!, only: [:edit, :update, :destroy] # GET /posts or /posts.json def index @posts = Post.all end # GET /posts/1 or /posts/1.json def show @post = Post.find(params[:id]) record_view(@post) end # GET /posts/new def new @post = Post.new end # GET /posts/1/edit def edit end # POST /posts or /posts.json def create @post = Post.new(post_params) @post.user = current_user respond_to do |format| if @post.update(post_params) format.html { redirect_to post_url(@post), notice: "Post was successfully created." } format.json { render :show, status: :ok, location: @post } else format.html { render :edit, status: :unprocessable_entity } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # PATCH/PUT /posts/1 or /posts/1.json def update respond_to do |format| if @post.update(post_params) format.html { redirect_to post_url(@post), notice: "Post was successfully updated." } format.json { render :show, status: :ok, location: @post } else format.html { render :edit, status: :unprocessable_entity } format.json { render json: @post.errors, status: :unprocessable_entity } end end end # DELETE /posts/1 or /posts/1.json def destroy @post.destroy! respond_to do |format| format.html { redirect_to posts_url, notice: "Post was successfully destroyed." } format.json { head :no_content } end end private # Use callbacks to share common setup or constraints between actions. def set_post @post = Post.find(params[:id]) end # Only allow a list of trusted parameters through. def post_params params.require(:post).permit(:body, :title) end def record_view(post) begin if current_user post.views.create(user_id: current_user.id) else post.views.create end rescue => e puts "Error creating view: #{e.message}" end end def authorize_user! unless current_user == @post.user flash[:alert] = "You are not authorized to perform this action." redirect_to root_path end end end
我是RoR新手,感觉漏了明显的修复点,试过移除@post.views_count里的@符号没用,而且代码里找不到views_count的定义,不知道该用什么显示浏览量。
解决方案
1. 修复nil:NilClass错误
这个错误说明渲染post.html时@post为nil,原因是部分需要@post的动作没触发set_post回调。修改before_action配置,把:show加入列表:
before_action :set_post, only: [:show, :edit, :update, :destroy]
同时把show动作里的@post = Post.find(params[:id])删掉,统一用回调初始化,避免重复代码。
2. 实现浏览量统计逻辑
你没有定义views_count方法,需要先完成View模型和关联的设置:
(1)创建View模型
运行以下命令生成模型并迁移数据库:
rails generate model View post:references user:references rails db:migrate
(2)设置模型关联
在Post模型中添加关联:
# app/models/post.rb class Post < ApplicationRecord has_many :views, dependent: :destroy belongs_to :user end
在User模型中添加反向关联(可选,用于查询用户浏览记录):
# app/models/user.rb class User < ApplicationRecord has_many :posts has_many :views, dependent: :destroy end
(3)显示浏览量
直接用关联集合的count方法获取总浏览量,修改post.html中的代码:
<h6 class="card-subtitle mb-2 text-secondary"><%= @post.views.count %> zhlédnutí</h6>
(可选)优化性能:添加计数器缓存
如果帖子浏览量很高,频繁调用count会影响性能,可以添加缓存字段:
- 生成迁移添加
views_count字段:
rails generate migration AddViewsCountToPosts views_count:integer default:0 rails db:migrate
- 在
View模型中添加回调更新计数器:
# app/models/view.rb class View < ApplicationRecord belongs_to :post belongs_to :user, optional: true # 允许匿名浏览 after_create :increment_post_views_count after_destroy :decrement_post_views_count private def increment_post_views_count post.increment!(:views_count) end def decrement_post_views_count post.decrement!(:views_count) end end
之后就可以用@post.views_count来显示浏览量,性能更优。
3. 优化浏览记录逻辑
目前的record_view会重复记录同一用户的浏览,若要避免重复计数,修改方法:
def record_view(post) # 同一用户浏览同一帖子只记录一次 return if post.views.exists?(user_id: current_user&.id) if current_user post.views.create(user_id: current_user.id) else post.views.create end rescue => e Rails.logger.error "Error creating view: #{e.message}" # 用日志替代puts,方便排查问题 end
内容的提问来源于stack exchange,提问作者Alikuwu
相关产品推荐
相关产品推荐

