Rails中如何让includes检测关联数据是否已预加载?
解决方案
你遇到的问题本质是:company.people.includes(:emails)会生成全新的ActiveRecord关系对象,完全忽略之前已预加载到内存中的数据——哪怕关联已经加载,这行代码还是会触发新查询,因为includes是针对关系链的预加载逻辑,而非针对已加载的内存集合。
在Rails 4.2.11版本中,没有原生的includes变体可以自动检查关联是否已加载,但你可以通过简洁的手动判断实现需求,无需额外写复杂助手:
def getAllCompanyEmails(company) people = company.people # 检查people关联及每个person的emails是否都已预加载完成 unless people.loaded? && people.all? { |person| person.association(:emails).loaded? } people = people.includes(:emails) end people.flat_map(&:emails) end
逻辑说明:
people.loaded?:判断当前公司的people关联是否已经加载到内存中person.association(:emails).loaded?:判断单个person的emails关联是否已预加载- 如果两者都满足,直接用内存中的数据通过
flat_map提取邮箱,不会触发任何额外查询;否则通过includes(:emails)批量预加载,彻底避免N+1问题
内容的提问来源于stack exchange,提问作者mjkaufer
相关产品推荐
相关产品推荐

