PERF: Allow preloading 'recent time read' for a user (#9076)

This will be used when serializing multiple user cards
This commit is contained in:
David Taylor 2020-03-03 13:57:46 +00:00 committed by GitHub
parent d23f7af3cb
commit 65cc61be7a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 43 additions and 3 deletions

View File

@ -1211,10 +1211,22 @@ class User < ActiveRecord::Base
self.user_emails.secondary.pluck(:email)
end
RECENT_TIME_READ_THRESHOLD ||= 60.days
def self.preload_recent_time_read(users)
times = UserVisit.where(user_id: users.map(&:id))
.where('visited_at >= ?', RECENT_TIME_READ_THRESHOLD.ago)
.group(:user_id)
.sum(:time_read)
users.each { |u| u.preload_recent_time_read(times[u.id] || 0) }
end
def preload_recent_time_read(time)
@recent_time_read = time
end
def recent_time_read
self.created_at && self.created_at < 60.days.ago ?
self.user_visits.where('visited_at >= ?', 60.days.ago).sum(:time_read) :
self.user_stat&.time_read
@recent_time_read ||= self.user_visits.where('visited_at >= ?', RECENT_TIME_READ_THRESHOLD.ago).sum(:time_read)
end
def from_staged?

View File

@ -2287,4 +2287,32 @@ describe User do
expect(user.approved).to eq(true)
end
end
describe "#recent_time_read" do
fab!(:user) { Fabricate(:user) }
fab!(:user2) { Fabricate(:user) }
before_all do
UserVisit.create(user_id: user.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 10)
UserVisit.create(user_id: user.id, visited_at: 2.days.ago, posts_read: 1, mobile: false, time_read: 20)
UserVisit.create(user_id: user.id, visited_at: 1.week.ago, posts_read: 1, mobile: false, time_read: 30)
UserVisit.create(user_id: user.id, visited_at: 1.year.ago, posts_read: 1, mobile: false, time_read: 40) # Old, should be ignored
UserVisit.create(user_id: user2.id, visited_at: 1.minute.ago, posts_read: 1, mobile: false, time_read: 50)
end
it "calculates correctly" do
expect(user.recent_time_read).to eq(60)
expect(user2.recent_time_read).to eq(50)
end
it "preloads correctly" do
User.preload_recent_time_read([user, user2])
expect(user.instance_variable_get(:@recent_time_read)).to eq(60)
expect(user2.instance_variable_get(:@recent_time_read)).to eq(50)
expect(user.recent_time_read).to eq(60)
expect(user2.recent_time_read).to eq(50)
end
end
end