如何避免N+1查询并在Active Admin表单上执行急切加载

5
我在Active AdminFormtastic)表单中遇到了一个N+1查询问题。当加载与belongs_to关联对应的选择输入时,会发生查询。相关模型上的display_name引用另一个belongs_to关联。以下是模型之间的关系:
:user 
   |-- belongs_to :alum 
                     |-- belongs_to :graduation_class
                                                   |-- year

以下是模型的相关部分:

app/models/user.rb

class User < ApplicationRecord
  ...
  belongs_to :alumn, optional: true, touch: true
  ...
end

app/models/alumn.rb

class Alumn < ApplicationRecord
  belongs_to :graduation_class, touch: true
  delegate :year, to: :graduation_class
  has_many :users
  ...
  def display_name
    "#{year}: #{last_name}, #{first_name} #{middle_name}"
  end
  ...
end

这是相关的 Active Admin 类:

app/admin/user.rb

ActiveAdmin.register User do
  ...
  includes :alumn, alumn: :graduation_class
  ...
  form do |f|
    f.inputs do
      f.input :alumn  # This is causing the N+1 query
      ...
    end
  end
  ...
end

生成f.input :alumn选择字段导致了graduation_class的N+1查询。这是因为Formtastic通过调用alumn.display_name来生成选择选项,而alumn.display_name会调用关联的graduation_class上的year方法。

我的问题是,如何在此表单中急切加载graduation_class?在Active Admin类中使用includes :alumn, alumn: :graduation_class似乎不起作用。

更新:

我可以从服务器日志中看到,GraduationClass已被加载,但仍然无法消除N+1查询:

GraduationClass Load (0.6ms)  SELECT "graduation_classes".* FROM "graduation_classes"
4个回答

5

我最终通过在admin字段上构建自定义集合来解决这个问题。以下是相关代码:

app/admin/user.rb

ActiveAdmin.register User do
  ...
  includes :alumn, alumn: :graduation_class
  ...
  form do |f|
    f.inputs do
      f.input :alumn, as: :select, 
        collection: Alumn.includes(:graduation_class).where(...)
                      .collect { |a| [ a.display_name, a.id ] }
      ...
    end
  end
  ...
end

这仍然会导致额外的查询,但速度更快。


2
嵌套 include 只需要使用哈希即可实现。
includes({:alumn => :graduation_class})

我尝试了 includes :alumn, { :alumn => :graduation_class },但它没有起作用。 - Tom Aranda
不包括“:alumn”。只有哈希值。 - Fallenhero
那也不起作用。我可以从服务器日志中看到GraduationClass正在被加载,但出于某种原因,它无法转换为表单。 - Tom Aranda

2
如果构建Formtastic选择输入会生成不必要的查询,请尝试使用pluck仅获取构建列表所需的字段。

2

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