Rails N + 1 com has_many aninhados

Aqui está algo que eu tropecei esta noite que parece um pouco estranho. Considere as seguintes relações:

class Posts < ActiveRecord::Base
belongs_to
:user
has_many
:post_images
end

class PostImage < ActiveRecord::Base
belongs_to
:post
end

class User < ActiveRecord::Base
has_many
:posts
end

Agora, vamos fingir que temos uma ação de índice que mostra 25 postagens e o usuário que criou a postagem. A maneira padrão de evitar o N + 1 (que todos sabemos de cor) é a seguinte:

def index
Post.includes(:user).limit(25)
end

E o cenário em que queremos mostrar todas as imagens e o usuário que criou a postagem? Sua primeira inclinação é:

def index
Post.includes(:user, :post_images).limit(25)
end

Mas, na verdade, isso não resolve totalmente o problema N + 1. O código acima carregará rapidamente as imagens da postagem, mas ainda precisará selecionar a postagem, por conjunto de imagens de postagem. A maneira “correta” é na verdade a seguinte:

def index
Post.includes(:user, {post_images: :post}).limit(25)
end

Estrondo. As postagens, por conjunto de imagens de postagem, não precisarão mais ser selecionadas. No entanto, isso parece … errado, mas funciona e faz sentido … mais ou menos. Não consegui encontrar uma explicação para isso nos documentos do Rails, especificamente para este cenário. Eu, pessoalmente, me deparei com esse cenário ao depurar um problema N + 1 que estava ocorrendo quando um conjunto de registros era serializado em json.

Independentemente disso, agora você sabe como resolver um n + 1 nessa situação.