在我的 Rails 5 应用程序中,构建 JSON API 并使用 Activestorage 存储附件:
为了避免访问不存在的附件,我使用此 if condition as shown in this answer但不幸的是,这个 if 条件会发出一个 SQL 查询来检查附件是否可用,导致 n+1 次查询,尽管我已经包含(预加载)了我拥有的记录的附件
如果我已经预加载了附件,如何在不访问数据库的情况下检查记录中是否存在附件?
我尝试使用.nil?但这会误报存在附件,即使没有(如下所示)
ActionView::Template::Error (to_model delegated to attachment, but attachment is nil):
if !product.logo.nil?
json.logo_img url_for(product.logo)
.attached?
检查有效,但会导致 n+1 次查询:
if product.logo.attached?
json.logo_img url_for(product.logo)
因此,虽然下面的代码看起来非常丑陋,但它确实有效,一次预加载所有记录的附件,但是当检查附件是否存在时 => 这会导致 n+1 次查询
json.array!(@some_records.includes(integrated_product: [company: [ logo_attachment: :blob ]])) do |one_record|
product ||= one_record.integrated_product
if !product.logo.attached?
json.logo_img url_for(product.logo)
elsif !product.company.logo.attached?
json.logo_img url_for(product.company.logo)
end
...
任何有关如何以正确方式处理此问题(预加载附件和避免 n+1)的想法都将受到赞赏。
更新:
我想要获得我传递的整个集合,包括带有和不带有附件的项目,搜索一个条件来检查已加载的项目是否有附件或者如果图像有附件则不显示
最佳答案
Rails 生成 has_one_attached
的集合方法关系。你可以这样做:
Product.all.with_attached_logo.map{|product| product.logo.attached? }
这将生成一个急切加载的查询。
假设您想在 views/products/index.htm.erb
中显示每个产品的 Logo
因此,让我们在 controllers/products_controller.rb
的 index
操作中设置 @products
变量
def index
@products = Product.all.with_attached_logo
end
这会将 Logo 附件加载到每个产品中(如果有的话)。现在我们可以创建产品索引页面而不会出现 N+1 问题,如下所示:
<% @product.each do |product| %>
<% if product.logo.attached? %>
<%= image_tag product.logo %>
<% else %>
<%= image_tag "product_logo_placeholder.jpg" %>
<% end %>
... the rest of the product's information ...
<% end %>
关于ruby-on-rails - 已连接 ActiveStorage : checking if .?对于预加载附件的集合(同时避免对 Attached? 方法进行 n+1 次查询),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58308897/