提问人:aldm 提问时间:7/6/2023 最后编辑:aldm 更新时间:7/31/2023 访问量:64
在 Rails 7 中没有 N+1 查询的 assciation 上取消默认范围
Unscope default scope on assciation without N+1 query in Rails 7
问:
假设我有以下模数:
Category
has_many :p roducts has_many :tags has_one :author 具有默认范围Product
Tag
Author
default_scope { where(active: true) }
现在,在显示类别时,我还想显示产品中的所有产品和标签,但我也希望包含来自非活动用户的标签。
最直接的解决方案是删除默认范围并创建显式范围,并在所有位置使用它。但问题是我需要添加很多地方,因此该解决方案不可行。
另一种选择是将新范围添加到Product
def all_tags
Tag.joins(:author).unscope(author: { where: :active }).where(product_id: id)
end
这可行,但可能导致 N+1 问题 如果每个公司有 10 个产品,每个产品平均有 5 个标签,它将对数据库运行 50 个查询,这不是我想要的。
有什么优雅的方法可以解决 N+1 问题吗?
当然,我可以在控制器中引导所有相关的标签,例如
@tags_per_product = Tag.joins(:author).unscope(author: { where: :active }).where(product_id: product_ids).group_by(&:product_id)
然后在视图中重用,但这看起来有点脏tags_per_product
在 Rails 中,找到简洁优雅的方式总是很重要的,所以我想在这里找到它
提前致谢
答:
0赞
aldm
7/31/2023
#1
我是这样解决的
在 tag.rb 中
has_one :author, lambda {
unscope(where: :active)
}
所以基本上这是可行的,在所有上下文中,我们都会返回被默认范围排除的作者
如果出于某种原因,我们需要包括那些仅在某些上下文中被排除在外的人,我可以通过引入新的
has_one :author_user
或类似的东西
评论
scope :all_tags, -> { tags.unscope(where: :archived)}