Drop Scorable concern
This commit is contained in:
+6
-7
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user