Mongoid中Eager loading未包含has_one关联的技术问题
解决Mongoid预加载has_one关联不生效的问题
嘿,我瞅了下你的代码,问题主要出在as_json的处理和预加载的配合上,咱们一步步来搞定它:
1. 先确认预加载的scope写法没问题
你的eager scope用includes([:opportunity, :risk])是对的,Mongoid对has_one和has_many的预加载语法是一致的,这部分不用改,但得注意关联的命名和外键是否匹配(后面会说)。
2. 修复as_json的实现
你当前的as_json方法里,调用super时又指定了include: [:opportunity, :risk],这其实会和预加载的逻辑冲突——相当于你已经预加载了关联,但序列化的时候又重新去加载了一遍,反而可能没用到预加载的数据。调整成这样:
def as_json(options={}) # 合并传入的options和默认要包含的关联,保留灵活性 super(options.merge(include: [:opportunity, :risk])) end
如果不需要外部传入的options覆盖默认关联,也可以更简单:
def as_json(options={}) super(include: [:opportunity, :risk]) end
3. 检查关联的外键是否正确
Mongoid默认用关联名_id作为外键,比如Risk模型里应该有proposal_id字段。如果你自定义了外键(比如叫proposal_ref),那得在关联里明确指定:
# Proposal模型里 has_one :risk, foreign_key: :proposal_ref # Risk模型里 belongs_to :proposal, foreign_key: :proposal_ref
要是没自定义外键,这步直接跳过就行。
4. 验证预加载是否真的生效
你可以在rails控制台里测试,打开查询日志看看:
# 开启调试日志,能看到所有Mongo查询 Mongoid.logger.level = Logger::DEBUG # 执行预加载查询 proposal = Proposal.eager.first # 访问关联,看会不会触发新的查询 proposal.risk proposal.opportunity
如果预加载生效,控制台只会输出3条查询(Proposal表、Opportunity表、Risk表各一次);要是每次访问关联都出新查询,那说明预加载没起作用,得回头检查关联定义。
5. 最终调整后的代码参考
把Proposal模型调整后,应该就能正常序列化预加载的关联了:
class Proposal include Mongoid::Document belongs_to :opportunity has_one :risk scope :eager, -> { includes(:opportunity, :risk) } def as_json(options = {}) super(options.merge(include: [:opportunity, :risk])) end end
再执行render json: {result: Proposal.eager.first},就能看到risk关联被正确包含在返回的JSON里啦~
内容的提问来源于stack exchange,提问作者Michael H.
相关产品推荐
相关产品推荐

