organizations.first.warehouses
будет извлекать warehouses
только на organization_id
. Ваш warehouse_join
не влияет на это отношение.
Кроме того, чтобы связанные объекты были доступны через отдельный объект запрашиваемой коллекции без дополнительных запросов к БД, вы должны использовать методы предварительной загрузки (активной загрузки), такие как includes
.
Например, если вы хотите получить список organizations
с их warehouses
, вы должны сделать это следующим образом:
orgs = organizations.includes(:warehouses)
# now you can access `warehouses` of each individual `organization` without extra DB queries
orgs.first.warehouses
orgs.second.warehouses
Насколько я знаюв ActiveRecord
невозможно (или не так просто) использовать includes
с пользовательским условием JOIN.
Но в вашем случае я бы не стал этого делать, есть другой способ. Используйте две отдельные ассоциации (по одной для каждого внешнего ключа):
class Organization < ActiveRecord::Model
# delegated warehouses
has_many :delegated_warehouses, class_name: "Warehouse",
foreign_key: "delegated_to_organization_id"
# owned, but not delegated to any other organization
has_many :owned_not_delegated_warehouses, -> { where(delegated_to_organization_id: nil) },
class_name: "Warehouse",
foreign_key: organization_id
def warehouses_under_responsibility
# do not do like this!!! those associations are for preloading only!
delegated_warehouses + owned_not_delegated_warehouses # wrong!!!
# the right way
Warehouse.where("coalesce(delegated_to_organization_id, organization_id, -1) = ?", id)
end
end
Теперь вы можете использовать ассоциации для отдельной предварительной загрузки (активной загрузки) warehouses
, которые находятся под ответственностью.
orgs = Organization.includes(:delegated_warehouses, :owned_not_delegated_warehouses)
orgs.each do |org|
# now you can access the associated records separately
owned_warehouses = org.owned_not_delegated_warehouses
delegated_warehouses = org.delegated_warehouses
# or use them all together
all_warehouses = owned_warehouses + delegated_warehouses
end
Примечание:
Эти ассоциации следует использовать только при предварительной загрузке складов, т. Е. Когда существует большая коллекция организаций, и вам нужно выбрать склады, за которые они отвечают.
Если у вас есть одна организация и вам нужно выбрать склады, за которые она отвечает, вы должны использовать другой подход, который показан в методе warehouses_under_responsibility
.
Важно понять, почему мы не сделали этого. Используйте тот же подход при предварительной загрузке. Это потому, что мы не можем заставить include
работать с пользовательским условием соединения, которое coalesce(delegated_to_organization_id, organization_id, -1) = organizations.id