我正在经历N+1 query problem在 Active Admin ( Formtastic ) 形式。当加载与 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
这是相关的事件管理类:
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
生成选择选项,后者又调用关联的 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"
最佳答案
我最终通过在 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
它仍然会导致额外的查询,但速度要快得多。
关于ruby-on-rails - 如何避免 N+1 查询并在 Active Admin 表单上执行预加载,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47065331/