Benito Serna
Ruby/Rails, TDD, Software...

10 Examples to learn when your ActiveRecord query will be executed

Do you struggle fixing N+1 queries because is hard for you to detect why ActiveRecord seems to ignore your “includes”?

Wouldn’t it be nice to just see some piece of code and know when the query will execute?

Well… this exercise will try to help you achieve this… to help you identify when a query will execute by just watching the code :)

Instructions

I will show you 10 code examples using ActiveRecord’s query interface, like includes, order and where.

For each code example you will:

  1. Try to identify when ActiveRecord will execute de query
  2. Compare your answer with the one I will provide after the example.
Warning!

If you are just starting, the excercises could be hard!… Don’t worry, that’s expected, with practice it will be easier!

Excercise 1

Post.includes(:comments).to_a

Answer
  • When calling to_a

Excercise 2

Post.includes(:comments).order(:id).to_a

Answer
  • When calling to_a

Excercise 3

Post.all.each do |post|
  post.comments
  post.sorted_comments.to_a
end

Answer
  • When calling each on Post.all.each
  • When calling to_a on post.sorted_comments

Excercise 4

Post.includes(:comments).each do |post|
  post.comments.to_a
end

Answer
  • When calling each on Post.includes(:comments).each

Excercise 5

Post.includes(:comments).each do |post|
  post.comments.order(:id)
  post.comments.order(:id).to_a
end

Answer
  • When calling each on Post.includes(:comments).each
  • When calling to_a on post.comments.order(:id).to_a

Excercise 6

Post.includes(:sorted_comments).each do |post|
  post.sorted_comments.to_a
  post.comments.to_a
end

Answer
  • When calling each on Post.includes(:sorted_comments).each
  • When calling to_a on post.comments.to_a

Excercise 7

Post.includes(:sorted_comments).each do |post|
  post.sorted_comments.first
  post.comments.first
end

Answer
  • When calling each on Post.includes(:sorted_comments).each
  • When calling first on post.comments.first

Excercise 8

Post.includes(:sorted_comments).map do |post|
  post.sorted_comments.last
  post.comments.last
end

Answer
  • When calling map on Post.includes(:sorted_comments).map
  • When calling last on post.comments.last

Excercise 9

Post.includes(:sorted_comments).sort_by(&:id).each do |post|
  post.sorted_comments.limit(1).first
  post.comments.to_a.limit(1).first
end

Answer
  • When calling sort_by on Post.includes(:sorted_comments).sort_by(&:id).each
  • When calling first on post.sorted_comments.limit(1).first
  • When calling first on post.comments.to_a.limit(1)

Excercise 10

Post.includes(:comments).where("comments.points > 5").references(:comments).each do |post|
  post.comments.to_a
  post.comments.order(:id).to_a
  post.comments.sort_by(&:id).to_a
end

Answer
  • When calling each on Post.includes(:comments).where("comments.points > 5").references(:comments).each
  • When calling to_a on post.comments.order(:id).to_a

Practice more…

Been able to identify when a query will execute, just by watching the code is an ability that will make you job, much more easy.

Maybe at the beginning it will be hard, but the more you practice the easier that it will be.

So if you already can answer all the excercises right, try to create your own excercises and practice until you feel confident of your ability.

Other thing that you could do is to actually run the code of each excercise and also experiment changing them to try to understand what’s happening. You can find the code on bhserna/when the query is executed