所以我在这里设置了社交书签式设置。 4个表:帖子,用户,评论和投票。主页只是指向帖子模型的索引页面并在Post.all
数组上运行循环并显示一些基本信息:title
,upvotes
- downvotes
(我称之为ti帖子的“得分”)。
现在我需要做的就是在(我猜)模型中按照他们的分数除以他们的相对创建时间(这个帖子创建的页面加载后多少秒)来订购这些帖子。 Rails在我的帖子对象中给了我一个created_at
列,我有一个投票表,看起来像这样:
class Post < ActiveRecord::Base
attr_accessible :id, :title, :url, :user_id, :comment_count, :agreement
has_many :votes
has_many :comments
belongs_to :user
end
class Vote < ActiveRecord::Base
attr_accessible :direction, :post_id, :vote_type, :user_id
belongs_to :user
belongs_to :post
belongs_to :comment
end
帖子模型中的ID与投票模型中的post_id相对应。
:direction
是一个布尔值。与投票相关联的0
和与downvoting相关联的1
。 Post_ID是投票的帖子的ID。
我应该如何订购这些帖子,以便他们在主页上的位置取决于他们的创作时间和他们的投票结果?
def index
@posts = Post.join(:votes).order(<???>)
end
ETA:@shweta在加入帖子和投票表的正确轨道上。然而,他的答案的选择部分不起作用。
答案 0 :(得分:4)
免责声明:我不知道ruby或rails,只有SQL。
shweta的答案看起来非常接近,所以我会尝试用一些SQL黑客和斜线来完成它:
按upvotes排序,然后按created_at
排序@posts = Post.joins(:votes).select("posts.id,sum(if(direction = 0, 1, -1)) as score,posts.created_at,OTHER_ATTRS_YOU_NEED").group("posts.id").order("score DESC,posts.created_at")
此外,要包含零投票的帖子,您需要进行左连接:
@posts = Post.joins("LEFT JOIN votes ON posts.id = votes.post_id").select("posts.id,sum(if(direction = 0, 1, -1)) as score,posts.created_at,OTHER_ATTRS_YOU_NEED").group("posts.id").order("score DESC,posts.created_at")
更新:以修复未投票帖子的排序:
@posts = Post.joins("LEFT JOIN votes ON posts.id = votes.post_id").select("posts.id,sum(if(direction = 0, 1, if(direction is null, 0, -1))) as score,posts.created_at,OTHER_ATTRS_YOU_NEED").group("posts.id").order("score DESC,posts.created_at")
更新2:提高了排名
如果你排除旧项目,你可能会得到一个空列表(例如在安静的日子里),这可能不是你想要的。您可能最好添加另一列进行排名,如下所示:
@posts = Post.joins("LEFT JOIN votes ON posts.id = votes.post_id").select(
"posts.id," +
"sum(if(direction = 0, 1, if(direction is null, 0, -1))) as score," +
"(sum(if(direction = 0, 1, if(direction is null, 0, -1))) * " +
" if(unix_timestamp() - unix_timestamp(posts.created_at) < 7200, 3, 1)) as rank," +
"posts.created_at,OTHER_ATTRS_YOU_NEED"
).group("posts.id").order("rank DESC,posts.created_at")
出于排名目的,这比不到2小时的帖子的分数增加了三倍。
答案 1 :(得分:1)
按upvotes排序,然后按created_at
排序@posts = Post.joins(:votes).select("posts.id,count(votes.id) AS vote_count,posts.created_at,OTHER_ATTRS_YOU_NEED").group("posts.id").order("vote_count DESC,posts.created_at")
按created_at排序然后upvotes
@posts = Post.joins(:votes).select("posts.id,count(votes.id) AS vote_count,posts.created_at,OTHER_ATTRS_YOU_NEED").group("posts.id").order("posts.created_at, vote_count DESC")
答案 2 :(得分:1)
所以你想按rating/(time elapsed since creation)
订购。它可以使用sort_by在纯Ruby中完成,但不如原始sql高效。
所以......在数据库上执行它需要自Post#creation以来计算Times。在Mysql上,你有TIMEDIFF(在Postres / Oracle / etc上可能有所不同)进行那种计算。 SQL会或多或少地包含(在轻/伪代码中):
class Post
def self.order_by_popularity
score = "sum(if(direction = 0, 1, -1)) as score"
votes_count = "count(votes.id) as votes_count"
time_elapsed = "ABS(Timediff(#{Time.now}, created_at)) as time_elapsed"
select("posts.*, votes.id, #{score}, #{votes_count}, #{time_elapsed}").
join(:votes).group("votes.id").
order "ABS(votes_count/time_elapsed)"
end
end
更新:汇总上面提到的所有建议(BTW join(:votes)默认是左连接)。我想知道是否有任何陷阱......
其中,vote_count将来自帖子的缓存列或加入+群组,如先前的评论所示。
旁注:我成功使用了这种类型的查询,所以我希望能指出正确的方向,但坦率地说,这可能需要比典型的stackoverflow帮助提供的测试/试用更多。