在遍历has_many:through关联时访问关联的连接模型

时间:2016-08-23 21:13:58

标签: ruby-on-rails activerecord

我有一种感觉,这是一个非常基本的问题,但由于某些原因我很难被它(Rails新手)所困扰,似乎无法找到答案(可能是我没有正确搜索)。 / p>

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

class User < ApplicationRecord
  has_many :contacts, through :user_contacts

class Contact < ApplicationRecord
  has_many :users, through :user_contacts

在users / show.html.erb中,我正在迭代单个用户的联系人,例如:

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

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

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

2 个答案:

答案 0 :(得分:1)

实际上还没有加载连接模型: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

答案 1 :(得分:1)

首先,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是一对一的连接。做这样的事情会更容易:

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

此外,由于您是Rails的新手,值得一提的是,在没有N + 1查询的情况下加载这些记录,您可以在控制器中执行以下操作:

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