2011-06-15 46 views
4

这是我现在遇到过很多次的事情,我很想知道如何做我想做的事情,或者建立并向Rails提交补丁。在我的应用程序很多时候,我还会有一些模型,看起来像这样:如何通过关联对象的相关联接模型访问has_many:无附加查询?

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, through: :memberships 
end 

class Membership 
    belongs_to :user 
    belongs_to :group 

    def foo 
    # something that I want to know 
    end 
end 

class Group 
    has_many :memberships 
    has_many :users, through: :memberships 
end 

我希望能够做的是从一个电话访问相关会员向协会没有做额外的查询。举例来说,我想做这样的事:

@group = Group.first 
@group.users.each do |user| 
    membership = user.membership # this would be the membership for user in @group 
end 

是否有Rails的东西,使这个?因为我知道,以达到我说的是结果的唯一方法是非常丑陋的,效率低下,这样的事情:

@group.users.each do |user| 
    membership = Membership.where(group_id: @group.id, user_id:user.id).first 
end 

是否ActiveRecord的具有内置的设施有些晦涩难懂,以实现这一目标?它似乎不会太难,它已经必须获取连接模型,以便正确检索关联,所以如果这个功能不存在,在我看来它应该。我遇到过很多次了,我准备卷起袖子解决问题。我能做什么?

更新:其他模式为这个,我可以使用,基本上得到我想要的东西是这样的:

@group.memberships.includes(:user).each do |membership| 
    user = membership.user 
end 

但从美学角度,因为我不是其实我不喜欢这样的解决方案对成员资格非常感兴趣,因为我是用户,对迭代加入模型而不是关联目标感觉不对。但是,这比我上面提到的其他方式要好得多(感谢Intridea的Ian Yang提醒我注意这一点)。

回答

2

如果你只是想访问成员的一些属性,还有一个丑陋伎俩

group.users.select('*, memberships.some_attr as membership_some_attr') 

它的工作原理,因为成员包括在JOIN含蓄。

更新

更重要的是,如果你在User

class User < ActiveRecord::Base 
    has_many :memberships 
    has_many :groups, through: :memberships 
    belongs_to :membership #trick, cheat that we have membership_id 
end 

现在添加一个丑陋伎俩:

group.users.select('*, memeberships.id as membership_id').includes(:membership).each do |user| 
    membership = user.membership 
end 
+0

我打算让这个打开一下,看看有没有干净呃方式去做,但我爱你的小肮脏的黑客。 :) – 2011-06-16 03:14:21

0

如果您要访问的数据连接上的属性表格,然后包括是一个相当干净的方式来做到这一点。

但是,从您的帖子看来,您似乎对成员资格有一种方法,希望对底层数据做一些智能工作。此外,它好像你想要做的两件事情有一个查询:

  1. 输出用户信息(这就是为什么你迭代在首位用户对象上,如果你只是想会员您原本就重复这些)。
  2. 为您的会员资格对象输出一些智能和处理的信息。

正如您已经注意到的,您在这里所做的任何事情都会让您感到奇怪,因为无论您将代码放在哪里,都不会觉得自己是正确的模型。

我通常认为这种感觉是需要另一个抽象层。考虑创建一个名为MembershipUsers的新模型(这是一个可怕的名字,但你可以想象一个不同的名字)。

以下是我的ad-hoc编码的尝试是未经测试,但应该给你的解决方案的想法:

class MembershipUser < User 
    def self.for_group(group) 
    select('memberships.*, users.*'). 
    joins('join memberships on memberships.user_id = users.id'). 
    where('memberships.group_id = ?', group.id) 
    end 
    def foo 
    # now you have access to the user attributes and membership attributes 
    # and you are free to use both sets of data for your processing 
    end 
end 

通过创建代表用户和他们的成员到指定的组类,你已经创建了一个foo方法感觉合适的上下文。我猜foo在没有特定用户的情况下没有多大意义,并且你在foo方法中引用了关联的用户。

-Nick(@ngauthier)

编辑:忘了把这个全循环:

class Group 
    def membership_users 
    MembershipUser.for_group(self) 
    end 
end 

# then iterate 
group.membership_users.each do |membership_user| 
    membership_user.user_name # a pretend method on user model 
    membership_user.foo # the foo method that's only on MembershipUser 
end 
0

你可以这样来做:

获取特定组成员中的所有用户:

其中group_array是您希望@user成为其成员的组的ID的数组。

@user = User.all(:包括=>:基团,:条件=> [ “memberships.group_id在()?”,group_array])第一

与逆向它:

@group =群组。(:包括=>:用户:条件=> [ “memberships.user_id在()?”,user_array])第一

0
users = Group.first.users.select("*, memberships.data as memberships_data, users.*") 

这会给你访问任何东西

相关问题