Присоединяйтесь к has_many_through в рельсах - PullRequest
0 голосов
/ 25 ноября 2018

У меня есть 3 модели, как показано ниже.

class Order
 belongs_to :item
 belongs_to :category
end

class Item
 has_many :orders
 belongs_to :category
end

class Category
 has_many :items
 has_many :orders, through: :items
end

Я хочу объединить таблицы как Order.joins(:item).joins(:category), но это не работает.

Требуемый SQL -

SELECT * FROM `orders` 
INNER JOIN `items` ON `items`.`id` = `orders`.`item_id` 
INNER JOIN `categories` ON `items`.`category_id` = `categories`.`id`

Надеюсь, ваша помощь.

Ответы [ 3 ]

0 голосов
/ 25 ноября 2018

Я немного сбит с толку, потому что Order и Item, как принадлежащие Category и Category, уже имеют has_many Orders с этой настройкой, опция :through не нужна.

Для вашего желаемого результата, я думаю, вы хотите сделатьвложенное объединение (заказ> элемент> категория) вместо нескольких объединений (заказ> элемент + категория)

https://guides.rubyonrails.org/active_record_querying.html#joining-multiple-associations

12.1.3.1 Присоединение к вложенным ассоциациям (одноуровневый) Статья.joins (comments:: guest)

Это производит:

ВЫБРАТЬ статьи. * ИЗ СТАТЕЙ ВНУТРЕННИЕ ОБЪЕДИНЯТЬ КОММЕНТАРИИ НА comments.article_id = Articles.id ВНУТРЕННИЕ ПРИСОЕДИНЯТЬСЯ Гость НА guest.comment_id = comments.id

Итак, вы должны сделать что-то вроде Order.joins(item: :category)

0 голосов
/ 25 ноября 2018

Правильный способ установить эти ассоциации:

class Order < ApplicationRecord
  belongs_to :item
  # This references items.category_id
  has_one :category, through: :item
end

class Item < ApplicationRecord
  has_many :orders
  belongs_to :category
end

class Category < ApplicationRecord
  has_many :item, through: :orders
  has_many :orders
end

Вы хотите удалить столбец orders.category_id (если он существует) и использовать косвенную связь через таблицу элементов, чтобы избежать дублирования.Семантика belongs_to и has_one может сбивать с толку, но belongs_to предполагает, что внешний ключ находится на этой модели (заказы), тогда как has_one размещает его на других моделях таблица (элементы).

Это позволит вам присоединиться к / включить / eager_load ассоциации с:

irb(main):002:0> Order.joins(:category)
  Order Load (1.4ms)  SELECT  "orders".* FROM "orders" INNER JOIN "items" ON "items"."id" = "orders"."item_id" INNER JOIN "categories" ON "categories"."id" = "items"."category_id" LIMIT $1  [["LIMIT", 11]]

И, как вы можете видеть, Rails будет обрабатывать присоединение к таблице присоединения (элементы)автоматически.

Если вы хотите, чтобы обе ассоциации были загружены, вы можете использовать хеш или просто перечислить оба:

Order.eager_load(item: :category) 
Order.eager_load(:item, :category)
0 голосов
/ 25 ноября 2018

Синтаксис, который вы ищете:

Order.joins(item: :category)

Проверьте здесь для получения дополнительной информации.

...