开发者

Eager load Paperclip's has_attached_file data?

开发者 https://www.devze.com 2023-03-16 05:37 出处:网络
Product has_many :assets Asset belongs_to :product Asset has_attached_file :photo using Paperclip (with all your standard Paperclip options; a few styles, S3 storage).

Product has_many :assets

Asset belongs_to :product

Asset has_attached_file :photo using Paperclip (with all your standard Paperclip options; a few styles, S3 storage).

If I form a Product query like p = Product.includes(:assets) I can call each of the actual attributes of Asset without incurring any additional database queries, like:

p = Product.includes(:assets)
p.each { |a| print a.assets.first.开发者_JAVA技巧title }

The title attribute on Asset (which is a database column) prints, no queries made.

To get the URL generated by Paperclip:

p = Product.includes(:assets)
p.each { |a| print a.assets.first.photo.url }

causes a separate additional query for each Product:

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

According to this G.Groups posting, I shouldn't be hitting the database with each pass through the loop, but I am.

Is there a way to not incur the additional database hit for each iteration, but gather all the data all at once? Am I overlooking something simple?

Rails 3.0.9, REE 1.8.7, Paperclip 2.3.11.

updated, fixed

The issue is that in my Paperclip settings, I have :product_id as part of the :path: :attachment/:product_id/:filename-:style.:extension, which is causing the additional Product query for each iteration through the loop.

By changing the query to p = Product.includes(:assets => [:product]).all, it removed the additional query.


We can get to the root of the problem much faster if you use one of the query analyzer plugins Try query-reviewer, or if you're using newrelic, the dev mode includes this. You'll get a stack trace for every query. I don't think it has anything to do with eager loading - if it did, you'd be getting extra Asset loads instead of Product loads.


I think you're overlooking something simple:

p = Product.includes(:assets).all

includes sets the relation to eager load the association, all does the actual query.

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

精彩评论

暂无评论...
验证码 换一张
取 消