Rails 6.1调用关联集合类方法后模型current_scope非nil异常问题
问题根本原因
这是Rails 6.1版本中ActiveRecord的current_scope上下文泄漏特性导致的异常行为:
当你调用author.blogs.foo_all时,author.blogs本身就是携带了author_id = 456过滤条件的关联作用域,这个作用域会被临时挂载到Blog类的current_scope上,并且在整个作用域的执行链路中默认向下继承。
你在类方法foo_all中调用的all并没有跳出当前关联作用域的上下文,而是直接继承了author.blogs的过滤条件。后续在这个执行链路中调用的所有Blog类查询,只要没有显式解除作用域,都会默认带上当前的current_scope过滤条件,哪怕是直接写Blog.count也不例外。
修复方案
方案1:按需显式解除作用域
如果只是部分查询需要全表数据,直接在查询前加unscoped即可清空当前的上下文作用域:
def baz # 全表查询Blog数量,不会携带author过滤条件 Blog.unscoped.count end
方案2:修改类方法实现,强制无作用域执行
如果foo_all本身不需要依赖传入的关联过滤条件,可以直接修改类方法内部逻辑,从根源避免作用域泄漏:
def self.foo_all # 强制unscoped执行,后续所有查询都不会继承外部关联的过滤条件 unscoped.each(&:bar) end
方案3:升级Rails版本
该作用域泄漏的问题在Rails 7及以上版本中已经做了优化,作用域的上下文传递范围被大幅收窄,不会再出现类全局查询默认继承关联作用域的问题,项目允许的情况下可以通过升级版本彻底解决。
内容的提问来源于stack exchange,提问作者hrdwdmrbl
相关产品推荐
相关产品推荐

