Drop Scorable concern

This commit is contained in:
David Heinemeier Hansson
2025-04-18 17:07:36 +02:00
parent 1114679c20
commit 7c76bdd96d
3 changed files with 6 additions and 83 deletions
+6 -7
View File
@@ -1,6 +1,6 @@
class Card < ApplicationRecord
include Assignable, Colored, DraftCommenting, Engageable, Eventable, Golden,
Messages, Notifiable, Pinnable, Closeable, Scorable, Searchable, Staged,
Messages, Notifiable, Pinnable, Closeable, Searchable, Staged,
Statuses, Taggable, Watchable
belongs_to :collection, touch: true
@@ -21,12 +21,11 @@ class Card < ApplicationRecord
scope :indexed_by, ->(index) do
case index
when "most_active" then ordered_by_activity
when "newest" then reverse_chronologically
when "oldest" then chronologically
when "latest" then latest
when "stalled" then ordered_by_staleness
when "closed" then closed
when "newest" then reverse_chronologically
when "oldest" then chronologically
when "latest" then latest
when "stalled" then chronologically
when "closed" then closed
end
end
-64
View File
@@ -1,64 +0,0 @@
module Card::Scorable
extend ActiveSupport::Concern
REFERENCE_DATE = Time.utc(2025, 1, 1)
included do
scope :ordered_by_activity, -> { order activity_score_order: :desc }
# Staleness is measured by the amount of activity_score lost since it was last updated.
# The factor 0.9 is chosen to make the decay curve closer to linear; an exponential
# curve would make recent items appear stale very quickly, due to the sharp dropoff.
scope :ordered_by_staleness, -> { order Arel.sql(
"coalesce(activity_score * (1 - power(0.9, julianday('now') - julianday(activity_score_at))), 0) desc"
) }
end
def rescore
score = calculate_activity_score
score_at = last_scorable_activity_at
update! \
activity_score: score,
activity_score_at: score_at,
activity_score_order: event_score_reference(score, score_at)
end
private
def calculate_activity_score
scorable_events.sum { |event| event_score(event) }
end
def event_score(event)
days_ago = (last_scorable_activity_at - event.created_at) / 1.day
event_weight(event) / (2**days_ago)
end
def event_weight(event)
case
when event.comment&.first_by_author_on_card? then 20
when event.comment&.follows_comment_by_another_author? then 15
when event.commented? then 10
else 0
end
end
def event_score_reference(score, activity_at)
# The reference score is used to make the activity score comparable
# across different cards, since it represents the card's activity
# level at a consistent point in time.
#
# We store this as log2 to tame the huge/tiny numbers we'd otherwise get
# when activity is far from the reference date.
days_diff = (activity_at - REFERENCE_DATE) / 1.day
Math.log2(1.0 + score) + days_diff
end
def last_scorable_activity_at
scorable_events.maximum(:created_at) || created_at
end
def scorable_events
events.where(action: :commented)
end
end
-12
View File
@@ -1,12 +0,0 @@
require "test_helper"
class Card::ScorableTest < ActiveSupport::TestCase
test "cards with no activity have a valid activity_score_order" do
card = Card.create! collection: collections(:writebook), creator: users(:kevin)
card.rescore
assert card.activity_score.zero?
assert_not card.activity_score_order.infinite?
end
end