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

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会影响性能,可以添加缓存字段:

  1. 生成迁移添加views_count字段:
rails generate migration AddViewsCountToPosts views_count:integer default:0
rails db:migrate
  1. 在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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.28 15:57:03