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.