显然,在我的 Rails 应用程序中,ActiveRecord 运行的 SQL 查询比我想要的要多。我有一个简单的一对多关系。对于每个包...</p>
class Package < ActiveRecord::Base
has_many :screenshots
end
…有几个截图…</p>
class Screenshot < ActiveRecord::Base
belongs_to :package
def image_url
"/screenshots/#{self.package.name}/#{self.id}_#{size}.png"
end
end
我的第一个简单任务是显示包含包和屏幕截图的索引页面。对于每个包,我想显示它的屏幕截图。截图图像的路径由包名决定。让我们举个例子,获取“3dchess”包的包记录:
pkg = Package.includes(:screenshots).find_by_name('3dchess')
如您所见,我已经预先加载了屏幕截图。ActiveRecord 运行这两个 SQL 查询:
Package Load (1.4ms) SELECT "packages".* FROM "packages" WHERE "packages"."name" = '3dchess' LIMIT 1
Screenshot Load (2.1ms) SELECT "screenshots".* FROM "screenshots" WHERE "screenshots"."package_id" IN (243)
我曾期望这可以在一个查询中完成,但我不介意这两个。但是当我在索引页面上显示 20 个屏幕截图时,我突然得到了 20 个额外的 SQL 查询。事实证明,它们是由Screenshot模型的虚拟属性“image_url”引起的。
我在我的模板中做什么:
<% @packages.each do |package| %>
<li>
<% if package.screenshots %>
<%= image_tag package.screenshots.first.image_url %>
<% end %>
</li>
<% end %>
并且每次调用“image_tag package.screenshots.first.image_url”都会运行一个 SQL 查询,例如:
SELECT "packages".* FROM "packages" WHERE "packages"."id" = $1 ORDER BY "packages"."id" ASC LIMIT 1
因此,尽管我在加载包时急切地加载屏幕截图 - 但反过来却不行。
或者换一种说法——这会创建上面提到的两个 SQL 查询:
pkg = Package.includes(:screenshots).find_by_name('3dchess')
但是当我尝试访问
pkg.package
然后 ActiveRecord 运行一个额外的查询来获取“包”信息,尽管它应该已经有了它们。
所以我的问题是:如何使 ActiveRecord 自动将反向引用从“屏幕截图”加载到“包”?