Ответ 1
Я полагаю, что includes
будет использовать запрос LEFT OUTER JOIN
, если вы выполняете условие в таблице, которое использует ассоциация includes
:
Group.includes(:user_group_cmb).where(user_group_cmbs: { user_id: 1 })
У меня нет никаких идей. Не могли бы вы дать мне какие-либо подсказки (например, ссылки на сайты). Любая помощь будет оценена.
Model1: GROUP(id, name)
Model2: USER_GROUP_CMB(id, user_id, group_id)
Ожидаемая инструкция SQL:
SELECT *
FROM groups AS g LEFT OUTER JOIN user_group_cmbs AS cmb
ON g.id = cmb.group_id
WHERE cmb.user_id = 1
Я попытался настроить ассоциации ниже, но я не знаю, что делать после этого.
class Group < ActiveRecord::Base
has_many :user_group_cmb
end
class UserGroupCmb < ActiveRecord::Base
has_many :group
end
Rails Версия: 3.1.1
Я полагаю, что includes
будет использовать запрос LEFT OUTER JOIN
, если вы выполняете условие в таблице, которое использует ассоциация includes
:
Group.includes(:user_group_cmb).where(user_group_cmbs: { user_id: 1 })
Rails 5+ позволяет выполнять следующие действия:
Group.left_outer_joins(:user_group_cmb)
http://api.rubyonrails.org/classes/ActiveRecord/QueryMethods.html#method-i-left_joins
Вы можете сделать это в rails 3.x независимо от того, ссылаетесь ли вы на таблицу или нет в предложении where:
Group.eager_load(:user_group_cmb)
... и он выполнит соединение с левым фокусом
Возможно, очень важно отметить, что использование включает, возможно, нежелательные побочные эффекты.
если фильтрованная ассоциация впоследствии охвачена областью, все исходная фильтрация исчезает
Как выясняется, по охвату фильтрованной ассоциации weve потерял любой фильтрация-как-побочный эффект, который мы достигли из включений. И это не из-за того, как мы искали.
Обязательно прочитайте полную статью и, альтернативно, драгоценный камень для этого.
Используйте пользовательский оператор соединений:
Group.joins("left outer join user_group_cmbs as cmb on groups.id = cmb.group_id")
.where("cmb.user_id = ?", 1)
Проблема с принятым ответом заключается в том, что он фактически будет использовать LEFT INNER JOIN
технически, потому что он не будет отображать записи, где user_group_cmbs. user_id
имеет значение null (что было бы причиной для LEFT OUTER JOIN
).
Рабочее решение - использовать #references
:
Group.includes(:user_group_cmb).references(:user_group_cmb)
Или еще более удобный #eager_load
:
Group.eager_load(:user_group_cmb)
Прочтите более подробное объяснение здесь.
Используйте has_and_belongs_to_many, если вам просто нужно связать пользователей с группами. Используйте has_many: через, если вам нужно сохранить дополнительную информацию о членстве.
Пример:
class User < ActiveRecord::Base
has_and_belongs_to_many :groups
end
class Group < ActiveRecord::Base
has_and_belongs_to_many :users
end
Не удалось прокомментировать предыдущий ответ, потому что у меня нет 50 репутации. Но вот как это сработало для меня, когда я столкнулся с ошибкой ниже
include-referenced ratio вызывает исключение StatementInvalid, жалуясь, что оно пропускает запись FROM-clause. Мне нужно добавить явный вызов join, который по умолчанию является внутренним.
Мне пришлось использовать .references и указать имя таблицы или для нее добавить в предложение FROM