ruby 在使用活动存储附件时获取N + 1查询

wljmcqd8  于 2022-12-22  发布在  Ruby
关注(0)|答案(1)|浏览(92)

这是我的代码,它提供了N +1查询。

class User < ApplicationRecord
  has_many_attached :resumes, dependent: :destroy
  has_many_attached :cover_letters, dependent: :destroy
end

class ResumesController < ApplicationController
  def new
    @user = User.includes(resumes_attachments: :blob).find(params[:user_id])
  end

  def create
    @user = User.includes(resumes_attachments: :blob).find(params[:user_id])

    if @user.resumes.attach(params[:user][:resume])
      redirect_to new_user_resume_path(@user)
    else
      render :new
    end
  end
end

我已经注解掉了视图中的所有内容,以确保那里没有发生任何事情。Bullet gem只在创建操作失败和render :new被触发时才抱怨。如果创建操作成功,Bullet gem不会给出任何错误。
但是当我检查服务器日志时,ActiveStorage::Blob被调用了这么多次。我错过了什么?我使用的是Rails 6。

    • 更新日期:**

下面是我的日志。

↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "13e9e539-8c45-473f-b849-9e459646a1a1"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.3ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "2581e71d-98e3-4edc-afb8-310e699dde00"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "59ad2a58-dafe-4983-83d0-ce27ba37ff01"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "6f3431c2-8bb7-4348-a9d9-d36a4e8ea6bb"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.5ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "ac925113-8f42-4d12-aa04-842a812e57ab"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "bd753376-408b-497b-b4f9-8cdd4c85c23e"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "d48b3658-bb81-472b-b9b9-8da341a55ab6"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
  ActiveStorage::Blob Load (0.2ms)  SELECT "active_storage_blobs".* FROM "active_storage_blobs" WHERE "active_storage_blobs"."id" = $1 LIMIT $2  [["id", "e098a866-e14d-4477-8f4d-bd48389d0831"], ["LIMIT", 1]]
  ↳ app/controllers/resumes_controller.rb:17:in `create'
    • 更新2**

我也试过User.with_attached_resumes.find(id),但还是同样的问题

    • 更新3**

下面是我的代码从new.html.erb

<%= form_with model: @user, url: user_resumes_path(@user), method: :post, local: true do |f| %>
        <div class='row'>
          <div class='col-md-12 col-sm-12'>
            <div class='statistic-item'>
              <%= f.file_field :resume, class: 'form-control file-field' %>
            </div>
          </div>
        </div>
        <div class='row mrg-top-30'>
          <div class='col-md-12 col-sm-12'>
            <div class='form-group text-center'>
              <%= f.submit 'Upload Resume', class: 'btn btn-primary theme-bg' %>
            </div>
          </div>
        </div>
<% end %>

解决方案

我设法解决了这个问题,但我不知道它为什么工作。基本上我必须包括cover_letters以及然后N +1查询得到解决。这是非常奇怪的,我必须包括cover_letters当我试图附加只是简历。以下是我的工作代码create行动

@user = User.includes(resumes_attachments: :blob, cover_letters_attachments: :blob).find(params[:user_id])

@user = User.with_attached_resumes.with_attached_cover_letters.find(params[:user_id])

如果有人对这种行为有解释,请让我知道。谢谢

6mw9ycah

6mw9ycah1#

最后,我找出了active_storage应用程序中N + 1查询的主要原因
所以在挖掘了一段时间之后,我意识到我们的应用程序正在使用UUID作为所有主键,然后我检查了active_storage的迁移文件,查看UUID是如何设置的,在那里我发现了一行错误的代码。
这是旧代码

t.foreign_key :active_storage_blobs, column: :blob_id, type: :uuid

这是固定代码

t.foreign_key :active_storage_blobs, column: :blob_id

修复迁移后,我的代码按预期工作,我没有得到N + 1查询,我不必包括cover_letters黑客来修复N + 1查询。

User.with_attached_resusmes.find(params[:user_id])

User.includes(resumes_attachments: :blob).find(params[:user_id])

以下是active_storage的最终迁移文件

def change
    create_table :active_storage_blobs, id: :uuid do |t|
      t.string   :key,        null: false
      t.string   :filename,   null: false
      t.string   :content_type
      t.text     :metadata
      t.bigint   :byte_size,  null: false
      t.string   :checksum,   null: false
      t.datetime :created_at, null: false

      t.index [:key], unique: true
    end

    create_table :active_storage_attachments, id: :uuid do |t|
      t.string     :name,     null: false
      t.references :record,   null: false, polymorphic: true, index: false, type: :uuid
      t.references :blob,     null: false, type: :uuid

      t.datetime :created_at, null: false

      t.index %i[record_type record_id name blob_id], name: 'index_active_storage_attachments_uniqueness',
                                                      unique: true
      t.foreign_key :active_storage_blobs, column: :blob_id
    end
 end

相关问题