Last Updated: February 25, 2016
·
840
· teonimesic

Evite links compostos por objetos em Rails

Em Rails, quando se tem um recurso aninhado (nested resource), acaba sendo muito conveniente fazer um link para os comentários de um post usando algo como:

<%= link_to "Ver Comentario", [comment.post, comment] %>

e o rails vai traduzir automaticamente para algo como /posts/4/comments/6. O problema disso é que esta linha aparentemente inocente vai gerar uma consulta N+1 no seu banco, pois a cada commentário ele vai buscar um post. É possível adicionar um includes para fazer eager loading dos posts em cada comentário, mas dependendo do escopo fazer eager loading pode ser bem difícil ou até não ser uma opção. E no melhor dos casos, ainda será feita uma consulta para todos os posts de cada comentário e colocado o objeto na memória.

Ao invés disso, use apenas:

<%= link_to "Ver Comentario", post_comment_path(comment.post_id, comment.id) %>

Apesar de um pouco mais verboso, o ganho em perfomance é espantoso. Se a perfomance estiver ruim, suspeite dos links inocentes!

Caso queira entender melhor o que pode estar causando lentidão no sistema, aconselho duas gems: bullet e rails footnotes. A gem bullet nem sempre vai te mostrar os casos de N+1, especialmente se os objetos já estiverem na memória do servidor ( mas ainda deixam a página mais lenta ), então aconselho olhar os logos do rails footnotes e procurar por queries ao banco muito parecidas.