加载has_many的一条记录并进行检查

时间:2009-10-27 19:05:30

标签: ruby-on-rails activerecord

我正在实施一个包含帖子和可投票评论的博客。

加载帖子时,我想急切加载当前用户对帖子评论的所有投票。

这样的东西(不起作用):

@post.comments.all(:joins => :votes, :conditions => ['votes.user_id = ?', current_user.id])

每个评论都有一个名为 rated_by?

的方法
def rated_by?(actor)
  votes.find_by_user_id(actor.id)
end

问题是ActiveRecord会为每个rated_by运行一个查询吗?打电话,即使我的@ post.comments finder加入了所有相关的投票。

我看了一下act_as_rateable插件,但它有同样的问题,为每条记录运行查询,而不是使用连接。

2 个答案:

答案 0 :(得分:3)

双重秘密编辑:我正在回答另一个问题并遇到了一些适合你的事情。这是涉及Thread.current全局哈希的一个疯狂的黑客攻击。可能根本没有建议,但它确实有效。

它涉及在评论

上创建第二个has_many投票关联
class Comment < ActiveRecord::Base
  has_many :votes
  belongs_to :post
  has_many :current_user_votes, :class_name => "Vote",
    :conditions => '`#{Vote.table_name}`.user_id = \
    #{Thread.current[:current_user].id}'
end

它还要求您在要调用这些方法的控制器中设置Thread.current [:current_user] = current_user。

然后你应该能够做到

@post.comments.find(:all, :include => :current_user_votes) 

要获取注释列表,只需加载:current_user_votes。一站式查询。如果您一次收到多个帖子,则可以执行此操作。

Post.find(:all, :include => { :comments => :current_user_votes},
  :conditions => ...) 

将填充一个帖子列表,并急切加载他们的评论,这些评论反过来每个人都会加载他们的current_user_votes。

原始答案(为子孙后代保留)

我认为在一个查询中只能选择一个模型急切加载所有相关关联。

你将获得的最好成就就是你所做的。选择所有一个模型,然后为每个模型仅加载与命名范围或查找器的相关关联。

这个不起作用的声明只是选择用户投票的评论。

@post.comments.all(:joins => :votes, 
  :conditions => ['votes.user_id = ?', current_user.id])

此语句选择同一组注释,但也会为所选注释加载所有投票。

@post.comments.all(:include => :votes, 
  :conditions => ['votes.user_id = ?', current_user.id])

你真正需要做的就是打电话给rated_by?在每个评论。您可以通过使用命名范围来最小化数据库影响。但老实说,我认为它不会有所改善。

如果你非常担心如此努力地打击数据库,你可以这样做:

class Post < ActiveRecord::Base
  has_many :comments
  has_many :votes, :through => :comments
  ...
end

class Vote < ActiveRecord::Base
  belongs_to :comments
  ...

  named_scope :made_by_user, lambda {|user| 
    {:conditions => {:user_id => user}}
  }
end

@users_votes = @post.votes.made_by_use(current_user)

@comments = @post.comments.find(:all, :include => :votes)

@comments.each{|comment|
  user_voted_this_on_this_comment = comment.votes & @user_votes
  ...
}

老实说,我认为值得付出努力。

P.S。有一个关于方法名称的Ruby约定,以问号结尾应始终返回一个布尔值。

答案 1 :(得分:1)

你需要使用

:include => :votes

连接不加载您的数据,它只是加入数据库中的查询。