diff --git a/app/models/debate.rb b/app/models/debate.rb index 67c0c0206..8017fba0e 100644 --- a/app/models/debate.rb +++ b/app/models/debate.rb @@ -21,6 +21,8 @@ class Debate < ActiveRecord::Base before_validation :sanitize_description before_validation :sanitize_tag_list + before_save :calculate_hot_score + scope :sorted_for_moderation, -> { order(flags_count: :desc, updated_at: :desc) } scope :pending_flag_review, -> { where(ignored_flag_at: nil, hidden_at: nil) } scope :with_ignored_flag, -> { where("ignored_flag_at IS NOT NULL AND hidden_at IS NULL") } @@ -102,6 +104,24 @@ class Debate < ActiveRecord::Base update(ignored_flag_at: Time.now) end + def calculate_hot_score + z = 1.96 # Normal distribution with a confidence of 0.95 + time_unit = 12.hours + start = Time.new(2015, 6, 15) + + n = cached_votes_total + comments_count / 3 + pos = cached_votes_up + comments_count / 3 + + phat = 1.0 * pos / n + + weigted_score = n == 0 ? 0 : + (phat + z*z/(2*n) - z * Math.sqrt((phat*(1-phat)+z*z/(4*n))/n))/(1+z*z/n) + + age_in_units = ((created_at || Time.now) - start) / time_unit + + self.hot_score = (age_in_units**3 + weigted_score * 1000).round + end + protected def sanitize_description @@ -111,5 +131,4 @@ class Debate < ActiveRecord::Base def sanitize_tag_list self.tag_list = TagSanitizer.new.sanitize_tag_list(self.tag_list) end - end diff --git a/spec/factories.rb b/spec/factories.rb index 9f4345d4d..e541c1b20 100644 --- a/spec/factories.rb +++ b/spec/factories.rb @@ -71,6 +71,10 @@ FactoryGirl.define do Flag.flag(FactoryGirl.create(:user), debate) end end + + trait :with_hot_score do + before(:save) { |d| d.calculate_hot_score } + end end factory :vote do diff --git a/spec/models/debate_spec.rb b/spec/models/debate_spec.rb index e5cbc4691..52d8c0740 100644 --- a/spec/models/debate_spec.rb +++ b/spec/models/debate_spec.rb @@ -181,4 +181,38 @@ describe Debate do end end + describe '#hot_score' do + let(:now) { Time.now } + + it "gets bigger for newer debates" do + old = create(:debate, :with_hot_score, created_at: now - 1.day) + new = create(:debate, :with_hot_score, created_at: now) + expect(new.hot_score).to be > old.hot_score + end + + it "gets bigger for debates with more comments" do + more_comments = create(:debate, :with_hot_score, created_at: now, comments_count: 10) + less_comments = create(:debate, :with_hot_score, created_at: now, comments_count: 1) + expect(more_comments.hot_score).to be > less_comments.hot_score + end + + it "gets bigger for debates with more positive votes" do + more_likes = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 5) + less_likes = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 1) + expect(more_likes.hot_score).to be > less_likes.hot_score + end + + it "gets bigger for debates with more confidence" do + more_confidence = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 1000, cached_votes_up: 700) + less_confidence = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 9) + expect(more_confidence.hot_score).to be > less_confidence.hot_score + end + + it "decays older debates, even if they have more votes" do + older_more_voted = create(:debate, :with_hot_score, created_at: now - 2.days, cached_votes_total: 1000, cached_votes_up: 900) + new_less_voted = create(:debate, :with_hot_score, created_at: now, cached_votes_total: 10, cached_votes_up: 9) + expect(new_less_voted.hot_score).to be > older_more_voted.hot_score + end + end + end