[英]How do I access attributes of the join model in a has_many :through association
[英]How can I access a has_many :through association object's relevant join model without additional queries?
這是我現在遇到過很多次了,我很想弄清楚如何做自己想要的事情,或者構建並提交一個補丁來向Rails提交。 在我的應用程序中,很多時候我會有一些看起來像這樣的模型:
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提醒我這一點)。
如果您只想訪問成員資格中的某些屬性,則有一個丑陋的竅門
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
您可以這樣操作:
獲取特定組成員資格內的所有用戶:
其中group_array是您希望@user成為成員的組的ID數組。
@user = User.all(
include: :groups, conditions: ["memberships.group_id in (?)", group_array]
).first
用以下方法將其反轉:
@group = Group.all(
include: :users, conditions: ["memberships.user_id in (?)", user_array]
).first
users = Group.first.users.select("*, memberships.data as memberships_data, users.*")
這將使您能夠訪問所有內容
如果您希望訪問的數據是聯接表上的屬性,則包括是一種非常干凈的方法。
但是,從您的帖子中看來,您似乎有一種關於成員資格的方法,該方法希望對基礎數據進行一些智能化處理。 另外,似乎您想對一個查詢做兩件事:
正如您所注意到的,您在這里所做的任何事情都感覺很奇怪,因為無論您將代碼放在何處,都不會感覺像是正確的模型。
我通常將這種感覺識別為需要另一個抽象層。 考慮創建一個名為MembershipUsers的新模型(這是一個糟糕的名字,但是您可以想到另一個模型)。
以下是我的臨時編碼嘗試,未經測試,但可以使您了解解決方案:
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
通過創建一個表示User及其指定組成員身份的類,您創建了一個foo方法合適的上下文。 我猜想,如果沒有特定用戶的上下文,foo就沒有多大意義,並且您在foo方法中引用了關聯的用戶。
-尼克(@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
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.