I am experiencing an N+1 query problem in an Active Admin (Formtastic) form. The query occurs when loading a select input that corresponds to a belongs_to
association. The display_name
on the associated model references another belongs_to
association. Here are the model relationships:
:user
|-- belongs_to :alum
|-- belongs_to :graduation_class
|-- year
Here are the relevant portions of the models:
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
This is the relevant Active Admin class:
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
The generation of the f.input :alumn
select field is causing an N+1 query on graduation_class
. This is because Formtastic generates the select options by calling alumn.display_name
which in turn invokes the year
method on the associated graduation_class
.
My question is, how can I eager load graduation_class
in this form? The includes :alumn, alumn: :graduation_class
in the Active Admin class does not seem to work.
Update:
I can see from the server log, that GraduationClass
is being loaded, but it still does not eliminate the N+1 query:
GraduationClass Load (0.6ms) SELECT "graduation_classes".* FROM "graduation_classes"
I finally solved this by building a custom collection on the admin
field. Here is the relevant code:
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
It still results in an extra query, but it is much faster.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With