0

如何在我的博客应用程序中设置 default_scope,以便索引按照模型中定义的算法对条目进行排序?

如果我要使用类似于 HackerNews 的公式进行排名算法,如下所示,我该如何在我的模型中定义它?

total_score = (votes_gained - 1) / (age_in_hours + 2)^1.5

votes_gained 变量依赖于 Active_Record_Reputation_System,在我看来是这样写的:

votes_gained = @post.reputation_value_for(:votes).to_i

最后,age_in_hours 非常简单

age_in_hours = (Time.now - @post.created_at)/1.hour

我如何使用这些数字来订购我的博客文章索引?我一直在试图弄清楚如何total_score在模型中正确定义,以便我可以将其添加到默认范围default_scope order("total_score DESC")或类似的东西中。直接替换没有奏效,我不确定如何“改写”公式的每个部分。

我应该如何定义total_score?非常感谢您的洞察力!

4

1 回答 1

1

既然不能依靠活动记录将公式翻译成 SQL,就得自己写。这里唯一的潜在问题是这不是一个独立于数据库的解决方案。

由于您使用的是 Postgres,您可以将您的范围定义为(我还没有测试过,所以让我知道它是否有效):

AGE_IN_HOURS = "(#{Time.now.tv_sec} - EXTRACT (EPOCH FROM posts.created_at))/3600"
TOTAL_SCORE = "(rs_reputations.value - 1)/((#{AGE_IN_HOURS}) + 2)^1.5"

default_scope joins("INNER JOIN rs_reputations ON rs_reputations.target_id = posts.id").where("rs_reputations.target_type = 'Post'").order(TOTAL_SCORE)

编辑:实际上这不起作用,因为就目前而言, Time.now 计算一次(当模型加载时),但每次提取记录时都需要重新计算。利用

default_scope lambda { order_by_score }

def self.order_by_score

    age_in_hours = "(#{Time.now.tv_sec} - EXTRACT (EPOCH FROM posts.created_at))/3600"
    total_score = "(rs_reputations.value - 1)/((#{age_in_hours}) + 2)^1.5"

    joins("INNER JOIN rs_reputations ON rs_reputations.target_id = posts.id").where("rs_reputations.target_type = 'Post'").order(TOTAL_SCORE)
end
于 2012-09-23T20:22:30.843 回答