2011-06-15 52 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.*") 

這會給你訪問任何東西

相關問題