rails7: 无登录的浏览量实现

基于 rails 的浏览量实现,使用 activeJob 功能
更新于: 2023-12-19 20:41:30
实现的浏览量效果
数据库 queue 方式入库

model

添加字段 views_count 用于记录浏览次数,并给默认值为0(这一步需要手动进行)

有个不好的地方: views_count 会添加到 created_at 之后。

# 在终端中运行(随便选一个喜欢的命名)
rails g migration AddViewsCountToPosts views_count:integer
rails db:migrate

最终 migration

class AddViewsCountToPosts < ActiveRecord::Migration[7.1]
  def change
    add_column :posts, :views_count, :integer, default: 0
  end
end

posts

app/controllers/posts_controller.rb

# app/controllers/posts_controller.rb

class PostsController < ApplicationController
  before_action :set_post, only: [:show]

  def show
    # 增加浏览量前检查是否已经浏览过
    unless cookies[:viewed_posts].to_s.split(',').include?(@post.id.to_s)
      @post.increment!(:views_count)
      cookies[:viewed_posts] = cookies[:viewed_posts].to_s + ',' + @post.id.to_s
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end
end

views

显示 <%= @post.views_count %>

<!-- app/views/posts/show.html.erb -->

<h1><%= @post.title %></h1>
<p><%= @post.content %></p>

<p>浏览量: <%= @post.views_count %></p>

配置 activeJob

添加 config/application.rb 配置,默认使用 inline 适配器。

其它实现:     config.active_job.queue_adapter = :sidekiq/Delayed Job/Resque

# config/application.rb

module YourAppName
  class Application < Rails::Application
    # 其他配置...

    # 默认情况下,Rails 使用 "Inline" 适配器
    # 无需显式配置,可以注释掉或者删除下面这行
    # config.active_job.queue_adapter = :inline

    # 其他配置...
  end
end

生成 activeJob

rails generate job IncrementViews

添加 job

路径在这里 app/jobs/increment_views_job.rb

# app/jobs/increment_views_job.rb
class IncrementViewsJob < ApplicationJob
  queue_as :default

  def perform(post_id)
    post = Post.find(post_id)
    post.increment!(:views_count)
  end
end

优化 posts

使用 IncrementViewsJob.perform_later(@post.id) 优化 views_count 的更新逻辑。

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  before_action :set_post, only: [:show]

  def show
    # 增加浏览量前检查是否已经浏览过
    unless cookies[:viewed_posts].to_s.split(',').include?(@post.id.to_s)
      IncrementViewsJob.perform_later(@post.id)
      cookies[:viewed_posts] = cookies[:viewed_posts].to_s + ',' + @post.id.to_s
    end
  end

  private

  def set_post
    @post = Post.find(params[:id])
  end
end

防止浏览器直接修改

只能简单防止别人修改,如果更严格的,需要借助其它手段,如 浏览器指纹/ip/再结合cookie 等手段。

cookies[:viewed_posts] = { value: cookie_value, httponly: true, }

参考