Caching sum privileged reaction scores (#15299)

* Caching sum privileged reaction scores

This relates to work on improving the feed.  Namely that in the current
proposal in PR #15240 I'm not accounting for how privileged users have
given feedback on an article.

With this change, I will now have a cached value on the articles table
that can be a proxy for how the privileged users have reacted.

In addition there's a small refactor that moves a constant to the
correct scoping object.

Dependent on #15283.

* Fixing method name to `exists?`

Prior to this commit, I was using `exist?` which doesn't work for
ActiveRecord::Relation objects.
This commit is contained in:
Jeremy Friesen 2021-11-08 12:50:08 -05:00 committed by GitHub
parent bff7cd1118
commit 95969eb973
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 51 additions and 3 deletions

View file

@ -2,12 +2,10 @@ module Admin
class PrivilegedReactionsController < Admin::ApplicationController
layout "admin"
PRIVILEGED_REACTION_CATEGORIES = %i[thumbsup thumbsdown vomit].freeze
def index
@q = Reaction
.includes(:user, :reactable)
.where(category: PRIVILEGED_REACTION_CATEGORIES)
.privileged_category
.order(created_at: :desc)
.ransack(params[:q])
@privileged_reactions = @q.result.page(params[:page] || 1).per(25)

View file

@ -460,6 +460,7 @@ class Article < ApplicationRecord
def update_score
self.score = reactions.sum(:points) + Reaction.where(reactable_id: user_id, reactable_type: "User").sum(:points)
update_columns(score: score,
privileged_users_reaction_points_sum: reactions.privileged_category.sum(:points),
comment_score: comments.sum(:score),
hotness_score: BlackBox.article_hotness_score(self),
spaminess_rating: BlackBox.calculate_spaminess(self))

View file

@ -5,8 +5,14 @@ class Reaction < ApplicationRecord
"thumbsdown" => -10.0
}.freeze
# The union of public and privileged categories
CATEGORIES = %w[like readinglist unicorn thinking hands thumbsup thumbsdown vomit].freeze
# These are the general category of reactions that anyone can choose
PUBLIC_CATEGORIES = %w[like readinglist unicorn thinking hands].freeze
# These are categories of reactions that administrators can select
PRIVILEGED_CATEGORIES = %w[thumbsup thumbsdown vomit].freeze
REACTABLE_TYPES = %w[Comment Article User].freeze
STATUSES = %w[valid invalid confirmed archived].freeze
@ -31,6 +37,7 @@ class Reaction < ApplicationRecord
.or(comment_vomits.where(reactable_id: user.comment_ids))
.or(user_vomits.where(user_id: user.id))
}
scope :privileged_category, -> { where(category: PRIVILEGED_CATEGORIES) }
validates :category, inclusion: { in: CATEGORIES }
validates :reactable_type, inclusion: { in: REACTABLE_TYPES }

View file

@ -0,0 +1,17 @@
module DataUpdateScripts
class UpdateEachArticlesPrivilegedUserPointCount
def run
# This code is "idempotent" in that it's calculating and caching a value stored elsewhere.
Article.find_in_batches do |articles|
articles.each do |article|
# Given that we have a default of 0, don't update if we
# don't have any reactions.
next unless article.reactions.privileged_category.exists?
article.update_column(:privileged_users_reaction_points_sum,
article.reactions.privileged_category.sum(:points))
end
end
end
end
end

View file

@ -0,0 +1,17 @@
require "rails_helper"
require Rails.root.join(
"lib/data_update_scripts/20211104200856_update_each_articles_privileged_user_point_count.rb",
)
describe DataUpdateScripts::UpdateEachArticlesPrivilegedUserPointCount do
it "updates articles scores" do
article = create(:article)
user = create(:user, :trusted)
reaction = create(:thumbsdown_reaction, user: user, reactable: article)
# Short-circuiting callbacks
reaction.update_column(:points, 1_000_000)
expect { described_class.new.run }.to change { article.reload.privileged_users_reaction_points_sum }.to(1_000_000)
end
end

View file

@ -1331,6 +1331,14 @@ RSpec.describe Article, type: :model do
article.update_score
expect { article.update_score }.not_to change { article.reload.hotness_score }
end
it "caches the privileged score values" do
user = create(:user, :trusted)
create(:thumbsdown_reaction, reactable: article, user: user)
expect { article.update_score }.to change { article.reload.privileged_users_reaction_points_sum }
end
end
describe "#feed_source_url and canonical_url must be unique for published articles" do