Proposals hot_score
This commit is contained in:
@@ -27,6 +27,8 @@ class Proposal < ActiveRecord::Base
|
||||
before_validation :sanitize_tag_list
|
||||
before_validation :set_responsible_name
|
||||
|
||||
before_save :calculate_hot_score, :calculate_confidence_score
|
||||
|
||||
scope :for_render, -> { includes(:tags) }
|
||||
scope :sort_by_hot_score , -> { order(hot_score: :desc) }
|
||||
scope :sort_by_confidence_score , -> { order(confidence_score: :desc) }
|
||||
@@ -87,6 +89,22 @@ class Proposal < ActiveRecord::Base
|
||||
"#{Setting.value_for("proposal_code_prefix")}-#{created_at.strftime('%Y-%M')}-#{id}"
|
||||
end
|
||||
|
||||
def after_commented
|
||||
save # updates the hot_score because there is a before_save
|
||||
end
|
||||
|
||||
def calculate_hot_score
|
||||
self.hot_score = ScoreCalculator.hot_score(created_at,
|
||||
cached_votes_up,
|
||||
cached_votes_up,
|
||||
comments_count)
|
||||
end
|
||||
|
||||
def calculate_confidence_score
|
||||
self.confidence_score = ScoreCalculator.confidence_score(cached_votes_up,
|
||||
cached_votes_up)
|
||||
end
|
||||
|
||||
def self.title_max_length
|
||||
@@title_max_length ||= self.columns.find { |c| c.name == 'title' }.limit || 80
|
||||
end
|
||||
@@ -126,6 +144,7 @@ class Proposal < ActiveRecord::Base
|
||||
self.responsible_name = author.document_number
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def validate_description_length
|
||||
|
||||
@@ -4,16 +4,16 @@ module ScoreCalculator
|
||||
COMMENT_WEIGHT = 1.0/20 # 1 positive vote / x comments
|
||||
TIME_UNIT = 12.hours.to_f
|
||||
|
||||
def self.hot_score(date, votes_total, votes_up, comments_count)
|
||||
total = votes_total + COMMENT_WEIGHT * comments_count
|
||||
ups = votes_up + COMMENT_WEIGHT * comments_count
|
||||
def self.hot_score(date, votes_total, votes_up, comments_count)
|
||||
total = (votes_total + COMMENT_WEIGHT * comments_count).to_f
|
||||
ups = (votes_up + COMMENT_WEIGHT * comments_count).to_f
|
||||
downs = total - ups
|
||||
score = ups - downs
|
||||
order = Math.log([score.abs, 1].max, 10)
|
||||
sign = (score <=> 0).to_f
|
||||
offset = Math.log([score.abs, 1].max, 10) * (ups / [total, 1].max)
|
||||
sign = score <=> 0
|
||||
seconds = ((date || Time.now) - EPOC).to_f
|
||||
|
||||
(((order * sign) + (seconds/TIME_UNIT)) * 10000000).round
|
||||
(((offset * sign) + (seconds/TIME_UNIT)) * 10000000).round
|
||||
end
|
||||
|
||||
def self.confidence_score(votes_total, votes_up)
|
||||
|
||||
@@ -142,4 +142,85 @@ describe Proposal do
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#hot_score' do
|
||||
let(:now) { Time.now }
|
||||
|
||||
it "increases for newer proposals" do
|
||||
old = create(:proposal, :with_hot_score, created_at: now - 1.day)
|
||||
new = create(:proposal, :with_hot_score, created_at: now)
|
||||
expect(new.hot_score).to be > old.hot_score
|
||||
end
|
||||
|
||||
it "increases for proposals with more comments" do
|
||||
more_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 25)
|
||||
less_comments = create(:proposal, :with_hot_score, created_at: now, comments_count: 1)
|
||||
expect(more_comments.hot_score).to be > less_comments.hot_score
|
||||
end
|
||||
|
||||
it "increases for proposals with more positive votes" do
|
||||
more_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 5)
|
||||
less_likes = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 1)
|
||||
expect(more_likes.hot_score).to be > less_likes.hot_score
|
||||
end
|
||||
|
||||
it "increases for proposals with more confidence" do
|
||||
more_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 700)
|
||||
less_confidence = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
|
||||
expect(more_confidence.hot_score).to be > less_confidence.hot_score
|
||||
end
|
||||
|
||||
it "decays in older proposals, even if they have more votes" do
|
||||
older_more_voted = create(:proposal, :with_hot_score, created_at: now - 2.days, cached_votes_up: 900)
|
||||
new_less_voted = create(:proposal, :with_hot_score, created_at: now, cached_votes_up: 9)
|
||||
expect(new_less_voted.hot_score).to be > older_more_voted.hot_score
|
||||
end
|
||||
|
||||
describe 'actions which affect it' do
|
||||
let(:proposal) { create(:proposal, :with_hot_score) }
|
||||
|
||||
it "increases with votes" do
|
||||
previous = proposal.hot_score
|
||||
5.times { proposal.register_vote(create(:user, verified_at: Time.now), true) }
|
||||
expect(previous).to be < proposal.reload.hot_score
|
||||
end
|
||||
|
||||
it "increases with comments" do
|
||||
previous = proposal.hot_score
|
||||
25.times{ Comment.create(user: create(:user), commentable: proposal, body: 'foobarbaz') }
|
||||
expect(previous).to be < proposal.reload.hot_score
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe "#confidence_score" do
|
||||
|
||||
it "takes into account votes" do
|
||||
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 100)
|
||||
expect(proposal.confidence_score).to eq(10000)
|
||||
|
||||
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 0)
|
||||
expect(proposal.confidence_score).to eq(0)
|
||||
|
||||
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 75)
|
||||
expect(proposal.confidence_score).to eq(7500)
|
||||
|
||||
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 750)
|
||||
expect(proposal.confidence_score).to eq(75000)
|
||||
|
||||
proposal = create(:proposal, :with_confidence_score, cached_votes_up: 10)
|
||||
expect(proposal.confidence_score).to eq(1000)
|
||||
end
|
||||
|
||||
describe 'actions which affect it' do
|
||||
let(:proposal) { create(:proposal, :with_confidence_score) }
|
||||
|
||||
it "increases with like" do
|
||||
previous = proposal.confidence_score
|
||||
5.times { proposal.register_vote(create(:user, verified_at: Time.now), true) }
|
||||
expect(previous).to be < proposal.confidence_score
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user