Это то, с чем я сталкивался уже несколько раз, и я хотел бы либо выяснить, как сделать то, что я хочу, либо создать, и отправить патч в 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 за напоминание мне об этом).