ruby-on-rails - 已连接 ActiveStorage : checking if .?对于预加载附件的集合(同时避免对 Attached? 方法进行 n+1 次查询)

标签 ruby-on-rails rails-activestorage

在我的 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.rbindex 操作中设置 @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/

相关文章:

javascript - ruby on Rails 4.2.6 "delete action"不工作

ruby-on-rails - ActionText gif 附件在提交 rails 表单时转换为照片

ruby-on-rails - Rails联接并包括联接表中的列

ruby-on-rails - 设计和谷歌oauth。 (ror3)

ruby-on-rails - 为什么在重新打开类(class)时有时会使用 class_eval?

ruby-on-rails - 查询数组内部值的事件记录

ruby-on-rails - 在保存到 ActiveStorage 之前重命名文件 - Rails 5.2

ruby-on-rails - OpenSSL::Cipher::CipherError Rails 5.2

ruby-on-rails - 获取 ActiveStorage 图像的完整 URL

ruby-on-rails - rails : How to disable ActiveStorage Analyzers and Previewers