0

显然,在我的 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 自动将反向引用从“屏幕截图”加载到“包”?

4

0 回答 0