Pre-calculate comment counts and activity scores
This commit is contained in:
@@ -9,7 +9,7 @@ module BubblesHelper
|
||||
|
||||
def bubble_size(bubble)
|
||||
rank =
|
||||
case bubble.activity_count
|
||||
case bubble.activity_score
|
||||
when 0..5 then "one"
|
||||
when 6..10 then "two"
|
||||
when 11..25 then "three"
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
class Account < ApplicationRecord
|
||||
include Joinable
|
||||
|
||||
has_many :users, dependent: :destroy
|
||||
|
||||
has_many :buckets, dependent: :destroy
|
||||
has_many :bubbles, through: :buckets
|
||||
|
||||
has_many :users, dependent: :destroy
|
||||
|
||||
has_many :workflows, dependent: :destroy
|
||||
has_many :stages, through: :workflows, class_name: "Workflow::Stage"
|
||||
|
||||
|
||||
+4
-13
@@ -10,19 +10,10 @@ class Bubble < ApplicationRecord
|
||||
|
||||
scope :reverse_chronologically, -> { order created_at: :desc, id: :desc }
|
||||
scope :chronologically, -> { order created_at: :asc, id: :asc }
|
||||
scope :ordered_by_activity, -> { order activity_score: :desc }
|
||||
scope :ordered_by_comments, -> { order comments_count: :desc }
|
||||
scope :in_bucket, ->(bucket) { where bucket: bucket }
|
||||
|
||||
# FIXME: Compute activity and comment count at write time so it's easier to query for.
|
||||
scope :left_joins_comments, -> do
|
||||
left_joins(:messages).merge(Message.left_joins_messageable(:comments))
|
||||
end
|
||||
scope :ordered_by_activity, -> do
|
||||
left_joins_comments.select("bubbles.*, COUNT(comments.id) + bubbles.boost_count AS activity").group(:id).order("activity DESC")
|
||||
end
|
||||
scope :ordered_by_comments, -> do
|
||||
left_joins_comments.select("bubbles.*, COUNT(comments.id) AS comment_count").group(:id).order("comment_count DESC")
|
||||
end
|
||||
|
||||
scope :indexed_by, ->(index) do
|
||||
case index
|
||||
when "most_active" then ordered_by_activity
|
||||
@@ -34,8 +25,8 @@ class Bubble < ApplicationRecord
|
||||
end
|
||||
end
|
||||
|
||||
def activity_count
|
||||
boost_count + messages.comments.size
|
||||
def rescore
|
||||
update! activity_score: boost_count + messages.comments.size
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
@@ -8,6 +8,7 @@ module Bubble::Boostable
|
||||
def boost!
|
||||
transaction do
|
||||
increment! :boost_count
|
||||
rescore
|
||||
track_event :boosted
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,4 +4,14 @@ class Comment < ApplicationRecord
|
||||
belongs_to :creator, class_name: "User", default: -> { Current.user }
|
||||
|
||||
searchable_by :body, using: :comments_search_index
|
||||
|
||||
def captured_as(message)
|
||||
message.bubble.increment! :comments_count
|
||||
message.bubble.rescore
|
||||
end
|
||||
|
||||
def uncaptured_as(message)
|
||||
message.bubble.decrement! :comments_count
|
||||
message.bubble.rescore
|
||||
end
|
||||
end
|
||||
|
||||
@@ -7,4 +7,10 @@ module Messageable
|
||||
has_one :message, as: :messageable, touch: true
|
||||
has_one :bubble, through: :message
|
||||
end
|
||||
|
||||
def captured_as(...)
|
||||
end
|
||||
|
||||
def uncaptured_as(...)
|
||||
end
|
||||
end
|
||||
|
||||
+11
-4
@@ -5,8 +5,15 @@ class Message < ApplicationRecord
|
||||
|
||||
scope :chronologically, -> { order created_at: :asc, id: :desc }
|
||||
|
||||
# FIXME: Will be made redundant when we compute activity and comment count at write time. See commit.
|
||||
scope :left_joins_messageable, ->(messageable_type) do
|
||||
joins "LEFT OUTER JOIN #{messageable_type} ON messages.messageable_id = #{messageable_type}.id"
|
||||
end
|
||||
after_create :captured
|
||||
after_destroy :uncaptured
|
||||
|
||||
private
|
||||
def captured
|
||||
messageable.captured_as(self)
|
||||
end
|
||||
|
||||
def uncaptured
|
||||
messageable.uncaptured_as(self)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddCommentsCountToBubbles < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :bubbles, :comments_count, :integer, null: false, default: 0
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
class AddActivityScoreToBubbles < ActiveRecord::Migration[8.0]
|
||||
def change
|
||||
add_column :bubbles, :activity_score, :integer, null: false, default: 0
|
||||
end
|
||||
end
|
||||
Generated
+3
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.0].define(version: 2024_11_13_185136) do
|
||||
ActiveRecord::Schema[8.0].define(version: 2024_11_15_234505) do
|
||||
create_table "accesses", force: :cascade do |t|
|
||||
t.integer "bucket_id", null: false
|
||||
t.integer "user_id", null: false
|
||||
@@ -92,6 +92,8 @@ ActiveRecord::Schema[8.0].define(version: 2024_11_13_185136) do
|
||||
t.integer "bucket_id", null: false
|
||||
t.integer "boost_count", default: 0, null: false
|
||||
t.integer "stage_id"
|
||||
t.integer "comments_count", default: 0, null: false
|
||||
t.integer "activity_score", default: 0, null: false
|
||||
t.index ["bucket_id"], name: "index_bubbles_on_bucket_id"
|
||||
t.index ["stage_id"], name: "index_bubbles_on_stage_id"
|
||||
end
|
||||
|
||||
Vendored
+4
@@ -6,6 +6,8 @@ logo:
|
||||
due_on: <%= 3.days.from_now %>
|
||||
created_at: <%= 1.week.ago %>
|
||||
boost_count: 5
|
||||
comments_count: 2
|
||||
activity_score: 7
|
||||
|
||||
layout:
|
||||
bucket: writebook
|
||||
@@ -13,6 +15,8 @@ layout:
|
||||
title: Layout is broken
|
||||
color: "#698F9C"
|
||||
created_at: <%= 1.week.ago %>
|
||||
comments_count: 1
|
||||
activity_score: 1
|
||||
|
||||
text:
|
||||
bucket: writebook
|
||||
|
||||
@@ -14,8 +14,10 @@ class BubbleTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "boosting" do
|
||||
assert_difference %w[ bubbles(:logo).boost_count Event.count ], +1 do
|
||||
bubbles(:logo).boost!
|
||||
assert_changes "bubbles(:logo).activity_score", +1 do
|
||||
assert_difference %w[ bubbles(:logo).boost_count Event.count ], +1 do
|
||||
bubbles(:logo).boost!
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,8 +35,8 @@ class BubbleTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test "ordering by activity" do
|
||||
bubbles(:layout).update! boost_count: 1_000
|
||||
assert_equal bubbles(:layout, :logo, :shipping, :text), Bubble.ordered_by_activity
|
||||
bubbles(:layout).tap { |b| b.update!(boost_count: 1_000) }.rescore
|
||||
assert_equal bubbles(:layout, :logo, :shipping, :text).pluck(:title), Bubble.ordered_by_activity.pluck(:title)
|
||||
end
|
||||
|
||||
test "ordering by comments" do
|
||||
|
||||
@@ -10,4 +10,18 @@ class CommentTest < ActiveSupport::TestCase
|
||||
|
||||
assert_includes Comment.search("something rustic"), message.comment
|
||||
end
|
||||
|
||||
test "updating bubble counter" do
|
||||
assert_changes "bubbles(:logo).activity_score" do
|
||||
assert_difference "bubbles(:logo).comments_count", 1 do
|
||||
bubbles(:logo).capture Comment.new(body: "I'd prefer something more rustic")
|
||||
end
|
||||
end
|
||||
|
||||
assert_changes "bubbles(:logo).activity_score" do
|
||||
assert_difference "bubbles(:logo).comments_count", -1 do
|
||||
bubbles(:logo).messages.comments.last.destroy
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user