У меня есть приложение Rails с рядом Продуктов, некоторые из которых связаны с моделью проблемы. Некоторые из этих продуктов имеют issue_id (так что проблема has_many
продуктов), а некоторые нет. Продукты без идентификатор проблемы - новое дополнение, над которым я работаю.Создание области ActiveRecord с несколькими условными выражениями
Я ранее имел именованный масштаб, так что я могу перечислить продукты, используя Product.published
, который выглядит следующим образом:
scope :published, -> {
joins(:issue).reorder('products.created_at ASC, products.number ASC')
.where('products.status = ?', Product.statuses[:available])
.where('issues.status = ?', Issue.statuses[:published])
}
Результат этого является то, что я могу найти только продукты, которые связаны с опубликованным выпуском (думаю журнал выпуск).
Теперь я добавляю продукты, которые не будут связаны с какой-либо конкретной проблемой, но все равно будут иметь проект/доступное состояние. Вышеуказанная область не находит эти продукты, поскольку она ищет not_ty_id, которая не существует.
Я думал, что я мог бы изменить сферу, как это, добавив OR issue_id IS NULL
часть в последней строке:
scope :published, -> {
joins(:issue).reorder('products.created_at ASC, products.number ASC')
.where('products.status = ?', Product.statuses[:available])
.where('issues.status = ? OR issue_id IS NULL', Issue.statuses[:published])
}
Но это не работает. Я все еще получаю только «доступные» продукты, связанные с «опубликованной» проблемой. Продукты без issue_id не включены в возвращенную коллекцию.
(Существует окно, в котором продукт будет установлен в имеющейся до его связанного вопроса публикуется, поэтому для таких ситуаций я должен проверить состояние обеих записей.)
Вот SQL порожденная выше (оболочкой для удобства чтения):
pry(main)> Product.published.to_sql
=> "SELECT `products`.* FROM `products` INNER JOIN `issues` ON `issues`.`id` =
`products`.`issue_id` WHERE (products.status = 1) AND (issues.status = 1 OR
issue_id IS NULL) ORDER BY products.created_at ASC, products.number ASC"
Я уже создал метод класса продукта, который принимает аргумент в качестве альтернативного подхода, но не работает во всех случаях, потому что я часто смотрю вверх продукт, основанный на идентификаторе, не зная заранее, существует ли ассоциация проблем o r нет (например, для продукта show вид).
Кроме того, Product.published
является приятным и лаконичным, и альтернативой является загрузка всех опубликованных продуктов (например, Product.where(:status => :published)
), а затем итерация, чтобы удалить те, которые связаны с еще не опубликованной проблемой во второй операции.
Я чувствую, что есть кое-что, что я не совсем понимаю, делая более сложные запросы в пределах области. Мой идеальный результат - это измененная область действия, которая может возвращать доступные продукты, как с проблемой, так и без нее, и без аргумента.
Возможно ли это, или я должен смириться с поиском альтернативного подхода, когда я добавляю эти несвязанные продукты?
Посмотрите на sql, сгенерированный этим запросом, используя, например, 'Product.published.to_sql' (отредактируйте свой вопрос и добавьте туда результат, чтобы мы все его могли видеть) :) Часто вы можете понять, почему SQL ошибается, а затем выполнить резервное копирование исправления, необходимого для области рубина. –
Хорошая идея @TarynEast, спасибо. Я добавил сгенерированный SQL, который я делал ранее, но я действительно не обмотал голову вокруг соединений, так что это не помогло мне увидеть проблему. – Kenn