Как я могу загрузить и присоединиться к условию полиморфизма? - PullRequest
0 голосов
/ 04 июля 2018

Вот мои модели:

class Team < ApplicationRecord
  has_many :team_permissions
end

class TeamPermission < ApplicationRecord
  belongs_to :team
  belongs_to :permissible, polymorphic: true
end

class User < ApplicationRecord
  has_many :team_permissions, as: :permissible
end

Я понимаю, что вы можете решить вашу проблему N + 1 с помощью включений следующим образом:

Team.includes(team_permissions: :permissible)

Теперь я хочу присоединить разрешения только при условии. Например, если они не принадлежат к группе идентификаторов, поэтому я ожидаю, что это сработает, но выдает ошибку.

ActiveRecord:

Team.includes(team_permissions: :permissible).where.not(team_permissions: { id: team_permission_ids })

Error:

ActionView::Template::Error (Cannot eagerly load the polymorphic association :permissible):

Играя с ним дальше, я обнаружил, что следующее работает так, как я хочу, но это не решает проблему N + 1.

Team.includes(:team_permissions).where.not(team_permissions: { id: team_permission_ids })

Как я могу включить стремительную загрузку для .includes с условием?

1 Ответ

0 голосов
/ 04 июля 2018

К сожалению, Active Record недостаточно умен (и, если честно, достаточно доверчив), чтобы понять, что ему нужно присоединиться к первой таблице, чтобы применить ваше условие, но не ко второй.

Вы должны быть в состоянии выручить это, будучи немного более явным:

Team.
  includes(:team_permissions).   # or eager_load(:team_permissions).
  preload(team_permissions: :permissible).
  where.not(team_permissions: { id: team_permission_ids }

Когда нет условий, ссылающихся на таблицы includes, по умолчанию используется preload, который обрабатывает N + 1, выполняя один дополнительный запрос, и совместим с полиморфными ассоциациями. Однако, когда такое условие найдено, все includes преобразуются в eager_load, что делает ЛЕВОЕ СОЕДИНЕНИЕ в основном запросе (и, следовательно, несовместимо: не может написать запрос, который объединяет к столам, о которых мы даже не знаем).

Выше я выделил часть, которую мы определенно хотим загрузить через preload, поэтому она должна работать правильно.

...