rails7: 无登录的浏览量实现
基于 rails 的浏览量实现,使用 activeJob 功能
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, }