Qual é a diferença entre isso:
User.includes(:sites).where("sites.name = 'test'").references(:sites)
e isto:
User.joins(:sites).where(sites: { name: "test"} )
Existe um consenso geral sobre o uso de um método em vez do outro?
Qual é a diferença entre isso:
User.includes(:sites).where("sites.name = 'test'").references(:sites)
e isto:
User.joins(:sites).where(sites: { name: "test"} )
Existe um consenso geral sobre o uso de um método em vez do outro?
Eles fazem coisas completamente diferentes.
.joins(:sites)
adiciona umINNER JOIN
à relação que limita os resultados a usuários com pelo menos um site antes da cláusula where ser aplicada.Nenhuma coluna da tabela unida será selecionada (a menos que você faça isso manualmente). Use-o quando quiser apenas filtrar os resultados com uma junção, mas não se importar com os dados na tabela relacionada ou com
.select
a seleção de agregados.Não impede consultas N+1 quando você acessa a associação:
.includes
evita consultas N+1 de forma "inteligente". É extremamente usado em excesso e geralmente é melhor pensar em como você quer usar os dados e usar os métodos aos quais ele delega diretamente.Ele tentará usar
.preload
para fazer duas consultas onde a primeira selecionaria os dados da tabela de usuários e a segunda consulta selecionaria os dados dassites
tabelas quando a associação for acessada pela primeira vez em qualquer membro da coleção. Isso evitará carregar os dados a menos que sejam realmente usados, ao mesmo tempo em que impede uma consulta N+1 para cada membro da associação.No entanto, se a consulta fizer referência à tabela de sites por meio da cláusula where,
.preload
isso não funcionará, pois não está unindo nada..includes
Na verdade, é inteligente o suficiente para detectar isso na maioria dos casos e usará.eager_load
para carregar tudo em uma única consulta com uma junção externa..references
diz explicitamente.includes
para usar.eager_load
e nesse exemplo evitará um driver de banco de dados que ocorre quando a consulta não se juntasites
.Mas se você apenas passar um hash
.where
em vez de sabotá-lo ativamente com uma string SQL para fins de exemplo, ele funciona perfeitamente:É ainda mais inútil se você considerar que você poderia simplesmente cortar o intermediário em vez de ser tão indeciso.
Acho que
.references
ainda poderia preencher uma função de nicho se você estiver construindo uma consulta programaticamente e quiser usar a natureza de carregamento lento,.includes
mas ao mesmo tempo evitar um erro de referência (esse cenário exigiu muita imaginação). Mas, em geral - YAGNI.