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

Tom*_*nda 5 ruby-on-rails formtastic activeadmin

我在Active Admin ( Formtastic ) 表单中遇到N+1 查询问题。当加载与关联对应的选择输入时,会发生查询。关联模型上的 引用另一个关联。以下是模型关系:belongs_todisplay_namebelongs_to

:user 
   |-- belongs_to :alum 
                     |-- belongs_to :graduation_class
                                                   |-- year
Run Code Online (Sandbox Code Playgroud)

以下是模型的相关部分:

应用程序/模型/user.rb

class User < ApplicationRecord
  ...
  belongs_to :alumn, optional: true, touch: true
  ...
end
Run Code Online (Sandbox Code Playgroud)

应用程序/模型/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
Run Code Online (Sandbox Code Playgroud)

这是相关的 Active Admin 类:

应用程序/管理/用户.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
Run Code Online (Sandbox Code Playgroud)

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

我的问题是,我怎样才能graduation_class以这种形式急切加载?Active Admin类includes :alumn, alumn: :graduation_class中的 似乎不起作用。

更新:

我可以从服务器日志中看到正在GraduationClass加载,但它仍然没有消除N+1查询:

GraduationClass Load (0.6ms)  SELECT "graduation_classes".* FROM "graduation_classes"
Run Code Online (Sandbox Code Playgroud)

Tom*_*nda 5

我最终通过在现场构建自定义集合解决了这个问题admin。这是相关代码:

应用程序/管理/用户.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
Run Code Online (Sandbox Code Playgroud)

它仍然会导致额外的查询,但速度要快得多。