迭代has_many时通过关联访问关联模型:通过关联

问题描述:

我有一种感觉,这是一个非常基本的问题,但由于某种原因,我被它困住了(Rails新手),似乎无法找到答案(这可能是我没有正确搜索)。迭代has_many时通过关联访问关联模型:通过关联

所以我有一个基本的has_many:通过这样的关系:

class User < ApplicationRecord 
    has_many :contacts, through :user_contacts 

class Contact < ApplicationRecord 
    has_many :users, through :user_contacts 

在用户/ show.html.erb我通过一个单一用户的联系人迭代,如:

<% @user.contacts.each do |c| %> 
    <%= c.name %> 
<% end %> 

现在,在每个循环内部,我想访问与给定用户和联系人关联的user_contact连接模型,以显示created_at时间戳,该时间戳指示用户何时建立了联系关系。

我知道我可以做一个UserContact.find调用,通过user_id和contact_id在数据库中查找模型,但不知何故,这感觉是多余的。如果我正确理解这是如何工作的(完全可能我不这样做),当我从数据库中加载给定用户及其联系人时,user_contact模型应该已经加载。我只是不知道如何正确访问正确的模型。有人可以帮助正确的语法?

其实加盟模式不会被加载尚未:ActiveRecord的取through规范来构建它的SQL语句JOIN查询正确Contact记录,但有效只会实例化的。

假设你有一个UserContact模型,你可以做某事像这样:

@user.user_contacts.includes(:contact).find_each do |uc| 
    # now you can access both join model and contact without additional queries to the DB 
end 

如果你想保留的东西可读,而不与uc.contact.something弄乱你的代码,你可以设置委托UserContact模型内部代表团一些属性分别为contactuser。例如,这

class UserContact < ActiveRecord::Base 
    belongs_to :user 
    belongs_to :contact 
    delegate :name, to: :contact, prefix: true 
end 

将允许你写

uc.contact_name 

首先,在has_many :things, through: :other_things条款是要去找other_things关系找到:things

把它看作是一种内置魔法的方法调用,使其在SQL查询中具有高性能。因此,通过使用一个through条款你或多或少做这样的事情:

def contacts 
    user_contacts.map { |user_contact| user_contact.contacts }.flatten 
end 

user_contacts的背景是完全丧失。

由于它看起来像user_contacts是一对一的连接。因为你是新来的Rails值得一提的是加载这些记录没有N + 1查询,你可以做这样的事情在你的控制器

<% @user.user_contacts.each do |user_contact| %> 
    <%= user_contact.contact.name %> 
<% end %> 

另外::这将是更容易做这样的事情

@user = User.includes(user_contacts: [:contacts]).find(params[:id]) 
+0

谢谢,得到了这个工作。对于任何在将来遇到此问题的人来说,包含的正确语法是在.find之前:@user = User.includes(user_contacts:[:contact])。find(params [:id]) – Katie

+0

Ahh,你是对的。 'find'不会返回'ActiveRecord :: Relation'。谢谢,我会解决它。 – Azolo

使用.joins.select这样:

@contacts = current_user.contacts.joins(user_contacts: :users).select('contacts.*, user_contacts.user_contact_attribute_name as user_contact_attribute_name')

现在,里面@contacts.each do |contact|循环,您可以拨打contact.user_contact_attribute_name

它看起来奇怪,因为contact不具有user_contact_attribute_name,只有UserContact做,但查询的.select部分将奇迹般地提供给您的每个contact实例。

contacts.*部分告诉查询使所有contact的属性都可用。