Rails 6 STI模式下查询父类因子类加载导致查询结果异常问题
Rails STI查询逻辑变化原因解析
这是Rails类加载机制和STI类型查询规则共同作用的正常现象,并非异常:
- 核心前提:Rails的STI查询父类记录时,默认会包含该父类所有子类的type值,SQL会生成
type IN (父类type, 所有子类type)的条件。而这个子类列表依赖Rails的类加载状态缓存。 - 开发环境下Rails默认开启类懒加载,只有当代码第一次用到对应类的时候才会加载该类的定义:
- 首次执行
User::Donor.first时,还没有触发过User::Legal的类加载,Rails不知道User::Donor存在子类,所以只会生成type = 'User::Donor'的查询条件,自然匹配不到type为User::Legal的记录,返回nil。 - 执行
User::Legal.first时,Rails会加载User::Legal的类定义,此时STI机制会自动更新父类User::Donor的子类缓存,将User::Legal加入User::Donor的可查询类型列表。 - 再次执行
User::Donor.first时,Rails已经获取到了User::Donor的完整子类列表,所以会生成type IN ('User::Donor','User::Legal')的查询条件,成功匹配到User::Legal的记录。
- 首次执行
规避方案
如果要在开发环境避免这个不一致的问题,可以在父类User::Donor的顶部主动声明加载子类:
require_dependency 'user/legal' class User::Donor < User end
生产环境下Rails会预加载所有类定义,不会出现这个问题。
内容的提问来源于stack exchange,提问作者mohsin_jamshaid
相关产品推荐
相关产品推荐

