我一直在使用ActiveRecord关联方法(例如在这篇文章Ryan's Scraps中)来执行一些更复杂的二级关联,同时最大限度地减少查询次数。例如,我使用以下关联从用户所关注的每个人中提取所有活动(以下是仅包含user_id和followed_user_id的模型):
class User < ActiveRecord::Base
<other associations, code, etc>
has_many :follows do
def activities(reload=false)
@followed_activities = nil if reload
@followed_activities ||= Activity.includes(:user, :comments, :comment_users).where(:user_id.in => self.collect {|e| e.followed_user_id}).order('activities.created_at DESC')
end
<.....>
end
这种方法非常有效,没有抱怨。但是,客户端已请求包含用户自身的活动(follow_users的活动+ current_user的活动)。
我意识到这可能是ruby 101,但我无法弄清楚如何从父(User)模型访问User.id。正如您在代码中看到的那样,self
引用了以下关系,并从下表中返回匹配行的列表。
我有时通过更改以下行来使其工作:
@followed_activities ||= Activity.includes(:user, :comments, :comment_users).where(:user_id.in => (self.collect {|e| e.followed_user_id}) << self.first.user_id).order('activities.created_at DESC')
然而,这a)感觉非常hackish,并且b)在没有任何跟随记录时引发异常(对于新用户总是如此)。我怎样才能获得用户ID?
答案 0 :(得分:2)
如the episode 215 Asciicast所示,你可以使用&
运算符合并两个关系,所以这样的东西应该有效:
@followed_activities ||= Activity
.includes(:user, :comments, :comment_users)
.where(:user_id.in => (self.collect {|e| e.followed_user_id})
@current_users_activity ||= Activity
.includes(:user, :comments, :comment_users)
.where(:user_id.in => [self.first.user_id] )
@all_activities ||= (@followed_activities & @current_users_activity).order('activities.created_at DESC')
编辑
注意:在rails 3.1中,&
运算符已弃用,请改用Relation#merge
。
做了一些有趣的研究。这绝对不是“红宝石101”!
实际上,代码中的self
确实引用了User
对象及其关联的Follow
记录之间的Association Proxy。当你像这样扩展一个关联时,你扩展了代理(因为我几乎不理解它,该块是instance_eval
d代理类。)
在rails&gt; = 3.1中,有一种方法可以在您的块中获取您的用户ID(请参阅this doc,“关联扩展”部分):
proxy_association.owner.id
所以你应该能够做到:
class User < ActiveRecord::Base
has_many :follows do
def activities( reload = false )
@followed_activities = nil if reload
@followed_activities ||= begin
Activity
.includes( :user, :comments, :comment_users )
.where( :user_id.in => [proxy_association.owner.id, *map( &:followed_user_id ) ])
.order( 'activities.created_at DESC' )
end
end
end
end