Rails, как запросить вложенную ассоциацию, возвращая все вложенные ассоциации

У меня есть следующие ассоциации:

class User < ApplicationRecord
  has_many :orders
end

class Order < ApplicationRecord
  belongs_to :user
  has_one :invoice
end

class Invoice < ApplicationRecord
  belongs_to :order
  has_one :receipt
end

class Receipt < ApplicationRecord
  belongs_to :invoice
end

Я хочу вернуть все квитанции по всем заказам пользователя.

Если бы отношения были один на один на протяжении всего пути, это было бы просто:

user = User.find(...)

user.order.invoice.receipt

Поскольку заказов много, мне хочется нанести на карту и сгладить. Я не хочу этого делать. Кажется, я не могу найти источники, которые помогли бы мне по-настоящему разобраться в этой концепции. Нужно ли мне определять отношение through? мне нужно использовать .joins?

Как я могу вернуть квитанцию ​​о всех заказах, принадлежащих конкретному пользователю?

0
0
483
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Это должно сработать для вас:

Receipt.joins(invoice: { order: :user }).where(users: { id: user_id })

Да, вам нужно использовать объединения, чтобы сгенерировать правильный запрос (объедините все таблицы по пути и добавьте свое пользовательское ограничение).

Другой вариант - использовать подзапрос.

users = User.where(id: user_id)
orders = Order.where(user_id: users)
invoices = Invoice.where(order_id: orders)
receipts = Receipt.where(invoice_id: invoices)

Вышеупомянутое должно выполнять один запрос при загрузке receipts. При копировании в терминал суффикс строк с ;nil предотвращает загрузку коллекций методом осмотреть (который используется для отображения возвращаемого значения терминала).


Примечание: Обычно вам нужно указать атрибут для выбора. Однако атрибут я бы (первичный ключ) выбирается неявно, не выбирая атрибут.

orders = Order.where(user_id: users)
# is the same as
orders = Order.where(user_id: users.select(:id))

Помните об этом, когда вам нужно создать подзапрос на основе другого атрибута, кроме я бы. Например, при изменении направления подзапроса.

users = User.where(id: orders.select(:user_id))

Вы даже можете опустить первую строку и предоставить user_id прямо в ограничение orders куда. orders = Order.where(user_id: user_id)

3limin4t0r 27.10.2018 13:48

Другие вопросы по теме