Ruby on rails 如何在联接后为返回的每个记录使用已加载的数据?

Ruby on rails 如何在联接后为返回的每个记录使用已加载的数据?,ruby-on-rails,eager-loading,Ruby On Rails,Eager Loading,在我的代码中,我加入了两个模型(例如Post和Comment),然后我加载了第三个模型(例如Author)。当我打印每条记录时,rails对Post的第一个实例使用急切加载的模型数据,但对Post的每个额外实例触发额外的数据库查询。这是一个n+1问题 我不明白的是,为什么我只能对每个帖子的第一条记录使用急切加载的数据,而不能使用join返回的其他记录 我曾研究过类似的问题,但我觉得这些问题并不是针对同一个问题。这些措施包括: ,及其他 我还特别研究了rails源代码,并尝试在本地对其进行

在我的代码中,我加入了两个模型(例如Post和Comment),然后我加载了第三个模型(例如Author)。当我打印每条记录时,rails对Post的第一个实例使用急切加载的模型数据,但对Post的每个额外实例触发额外的数据库查询。这是一个n+1问题

我不明白的是,为什么我只能对每个帖子的第一条记录使用急切加载的数据,而不能使用join返回的其他记录

我曾研究过类似的问题,但我觉得这些问题并不是针对同一个问题。这些措施包括:

  • ,及其他
我还特别研究了rails源代码,并尝试在本地对其进行一些修改,看看是否可以缩小问题的范围,或者问题是否发生在这里。我原以为这个类可能是在按id剥离非唯一记录实例(我认为它在第92行),但当我更改这个时,我的问题并没有得到解决

我确实偶然发现了这一点,这似乎是适用的,但在我的实际代码中,我使用的是
find_by_sql
,并没有能够有效地实现这一点

我已经创建了一个我正在体验的和我正在获得的输出。任何帮助都将不胜感激


注意:这个示例是我能想到的最简单的设置,它演示了我在实际代码中遇到的相同问题。在我的示例中,我知道我可以急切地加载注释和作者,但是,在我的实际代码中有一个更复杂的连接,并且需要连接。我无法从这个示例中加载注释模型

对于那些在未来发现这一点的人,以下是我的发现和实施

简单的要点示例 对于我的要点中概述的简单示例,我发现我可以通过更改以下内容获得所需的结果

要点:

# Triggers n+1 for author after first puts of an author.
posts = Post.joins(:comments).select("posts.*, comments.body").includes(:author)
posts.each do |x|
  puts "#{x.title} #{x.author.name} #{x.body}"
end
改为:

# Works as expected.
posts = Post.joins(:comments, :author).select("posts.*, comments.body").includes(:author)
posts.each do |x|
  puts "#{x.title} #{x.author.name} #{x.body}"
end
通过加入
作者
我不需要额外的查询就可以得到我想要的结果

更复杂的示例和实现 虽然上面解决了我用来演示问题的简单示例,但在我更复杂的实际问题中(如我的问题中所述),我无法实现这个额外的连接来解决问题

相反,我实现了查询对象模式和装饰器模式,如本文和github上的rails手册(和)中所述

这些模式允许我获得急切加载我想要的特定关联的所有好处,但对于我复杂得多的查询