急切加载Paperclip的has_attached_file数据?

3

产品 has_many :资产

资产 belongs_to :产品

资产 has_attached_file :photo 使用 Paperclip(包含所有标准的 Paperclip 选项;一些样式、S3 存储)。

如果我形成一个 Product 查询,例如 p = Product.includes(:assets),我可以调用 Asset 的实际属性而不会产生额外的数据库查询,例如:

p = Product.includes(:assets)
p.each { |a| print a.assets.first.title }
< p > Asset 上的 title 属性(数据库列)会直接输出,不进行任何查询。 < p > 要获取 Paperclip 生成的 URL:
p = Product.includes(:assets)
p.each { |a| print a.assets.first.photo.url }

会为每个产品引起一个单独的额外查询:

Product Load (0.3ms)  SELECT "products".* FROM "products" WHERE "products"."id" = 2 LIMIT 1

根据这篇G.Groups帖子,我不应该在每次循环中访问数据库,但实际上却是这样的。有没有办法避免每次迭代时都要进行额外的数据库查询,而是一次性收集所有数据?我是否忽略了一些简单的东西?
Rails 3.0.9,REE 1.8.7,Paperclip 2.3.11。
更新,修复
问题在于我的Paperclip设置中,我将:product_id作为:path的一部分::attachment/:product_id/:filename-:style.:extension,这导致每次循环都会进行额外的Product查询。
通过将查询更改为p = Product.includes(:assets => [:product]).all,可以消除额外的查询。

我在我的机器上测试了您的场景,一切都按预期工作。您能否发布一个 pastie 链接到实际错误代码? - Harish Shetty
2个回答

0

我认为你忽略了一些简单的东西:

p = Product.includes(:assets).all

includes设置关联预加载,all执行实际查询。

irb(main):001:0> p = Product.includes(:assets)
=> ..........
irb(main):002:0> p.class
=> ActiveRecord::Relation
irb(main):003:0> p.all.class
=> Array

我不相信在Rails 3+中.all是必要的,因为它是默认值。从我的日志来看,Product.includes(:assets)给了我第一个查询的SELECT "products" . * FROM "products",第二个查询的SELECT "assets" . * from "assets" WHERE ("assets".product_Id IN (...big list...) - jaacob
includes 调用返回一个关系,它实际上不执行查询。请参见这里。 它不像 all 一样是一个查找器方法。尝试添加它。 - Luke
谢谢提供的链接。不幸的是,这并没有解决我的问题。当我运行p.each { |a| print a.assets.first.photo.url }时,无论我是否包含.all,每找到一个产品,我仍然会得到额外的查询Product Load (0.5ms) SELECT "products".* FROM "products" WHERE "products"."id" = # LIMIT 1 - jaacob
你是否收到一个初始查询,加载所有的产品? - Luke
是的,日志显示 Product Load (61.0ms) SELECT "products".* FROM "products" Asset Load (78.5ms) SELECT "assets".* FROM "assets" WHERE ("assets".product_id IN (all the matching product_ids)。我在irb中也看到了和你一样的结果;Product.includes(:assets) 是一个 AR::Relation,而 Product.includes(:assets).all 则是一个数组。 - jaacob
显示剩余4条评论

0
如果您使用查询分析器插件之一,例如query-reviewer,或者如果您正在使用newrelic,则可以更快地找到问题的根源。开发模式包括此功能,您将为每个查询获取堆栈跟踪。我认为这与急切加载无关 - 如果是这样,您将会得到额外的资产加载而不是产品加载。

我安装了查询审查工具,但每个页面都显示零个查询,尽管我可以在日志中看到它们全部触发。我会再次仔细检查我的安装并重试。 - jaacob
尽管这并没有解决问题,但是你关于它不是由于 Asset 加载而不是急切加载的评论让我走上了自己找出答案的正确道路,因此我授予你赏金。 - jaacob

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接