我有一个包含许多产品的 Rails 应用程序,其中一些产品与问题模型相关联。其中一些产品有一个 issue_id(因此一个问题 has_many
产品)而有些则没有。 没有问题 ID 的产品是我正在开发的新产品。
我以前有一个命名范围,因此我可以使用 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])
}
这样做的结果是,我只能找到与已出版的期刊(想想杂志期刊)相关的产品。
我现在添加的产品不会与特定问题相关联,但仍处于草稿/可用状态。上述范围找不到这些产品,因为它查找不存在的 issue_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"
我已经创建了一个 Product 类方法,该方法采用参数作为替代方法,但并非在所有情况下都有效,因为我经常根据 ID 查找产品,而事先不知道是否存在 Issue 关联或不(例如,对于产品的显示 View )。
此外,Product.published
简洁明了,另一种方法是加载所有已发布的产品(例如,Product.where(:status => :published)
)然后在第二次操作中迭代以删除与尚未发布的问题相关的问题。
我觉得在一个范围内进行更复杂的查询时,我不太了解某些事情。我的理想结果是经过修改的范围可以返回可用产品,无论有无问题,并且不提供参数。
这可能吗,还是我应该放弃自己寻找替代方法,因为我正在添加这些不相关的产品?
最佳答案
问题是您正在使用 joins(:issue)
。该方法在 products
和 issues
表之间执行 INNER JOIN
并丢弃所有没有 issue_id 的产品。也许您可以使用 LEFT JOIN
,这样您就可以保留所有产品,而不管它们是否存在问题。
scope :published, -> {
joins('LEFT JOIN issues ON issues.id = products.issue_id')
.select('products.*')
.reorder('products.created_at ASC, products.number ASC')
.where('products.status = ?', Product.statuses[:available])
.where('issues.status = ? OR products.issue_id IS NULL', Issue.statuses[:published])
}
关于ruby-on-rails - 使用多个条件创建 ActiveRecord 范围,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/40119051/