ruby-on-rails – 如何通过关联对象的相关联接模型访问has_many:而无需其他查询?

这是我现在遇到过很多次的事情,我很想知道如何做我想要的或构建并向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
点赞