对于这种情况,最有效的rails加入呼叫

时间:2013-10-15 22:57:47

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-4

我的模特是:

class Link < ActiveRecord::Base
    has_many :votes
    belongs_to :user
end

class Vote < ActiveRecord::Base
    belongs_to :user
    belongs_to :link
end

class User < ActiveRecord::Base

    has_secure_password

    has_many :links
    has_many :votes
end

我有一个页面,列出系统中的所有链接。对于每个链接,我想显示所有投票的当前总和以及发出请求的用户是否已对该特定链接进行投票(如果是,那么该投票的值是多少)。我想以最有效的方式做到这一点。

目前,为了在链接控制器中返回我拥有的链接和总票数:

def index
    @links = Link.all(:joins => :votes, :select => "links.*, sum(votes.value) as votes_total", :group => "links.id")
end

效果很好,只需一次通话即可获得我的所有信息。所以我的问题是,我是否需要进行第二次查询以返回current_user的投票(如果存在),或者我可以将其合并到我的第一个查询中吗?

另外,也许我应该在数据库中设置某种sum_caching,但我不确定最好的方法。有什么想法吗?

1 个答案:

答案 0 :(得分:0)

你可以这样做:

@links = Link.
  joins(:votes). 
  select(
    "links.*, sum(votes.value) as votes_total, sum(case votes.user_id when #{current_user.id} then votes.value else 0 end) as current_vote", 
    :group => "links.id"
  )

这会为您提供当前用户的投票值@links.first.current_vote。当然,如果您的系统的投票值为零,则不区分“当前用户在此链接上投票0”和“当前用户未在此链接上投票”。我想你可以添加另一个选定的值(sum(case votes.user_id when #{current_user.id} then 1 else 0 end) as current_vote_exists)来处理它。

当然,在插入这样的SQL时要非常小心,和/或查找ActiveRecord附带的SQL消毒工具。

相关问题