
June 19, 2025
Yesterday morning, I had a deep and enjoyable technical interview covering a wide range of topics. But there was one moment I can’t forget: I completely fumbled a question about avoiding the N+1 problem in Rails.
Maybe it was the lack of coffee ☕ — or just nerves — but my brain didn’t cooperate, and ironically, the example I gave was the N+1 problem itself. 😅
So I did what any good developer should: I spent the afternoon (and part of this morning) revisiting my trusted Rails books and docs to refresh my knowledge. Here’s a breakdown of the problem — and the right ways to handle it.
❌ The N+1 Anti-pattern
User.all.each do |user|
user.articles.each do |article|
puts article.title
end
end
What happens here?
- 1 query to get all users.
- 1 additional query per user to get their articles.
That’s N+1 queries, and it kills performance as data grows.
✅ The Right Solutions

1. includes — Eager Loading
User.includes(:articles).each do |user|
user.articles.each do |article|
puts article.title
end
end
🔹 Rails runs 2 queries only: One for users, and one for all articles using WHERE user_id IN (…).
Use it when you’re displaying associated data without filtering or sorting it.
2. preload — Always Separate Queries
User.preload(:articles).each do |user|
user.articles.each do |article|
puts article.title
end
end
🔹 Forces Rails to run separate queries for each association (like includes, but never uses JOINs). Good when you’re not using conditions or order clauses on the associated table.
3. eager_load — SQL JOIN
User.eager_load(:articles).each do |user|
user.articles.each do |article|
puts article.title
end
end
🔹 Uses a LEFT OUTER JOIN to load everything in one query. Best when you need to filter or sort based on attributes in the joined table (e.g., articles.published_at DESC).
4. Optimizing with pluck or select
If you only need a few fields:
User.includes(:articles).each do |user|
user.articles.pluck(:id, :title)
end
Or more advanced optimization with joins and select:
User.joins(:articles).select('users.*, articles.title AS article_title').each do |user|
puts user.article_title
end
💡 Bonus: Detect N+1 Issues Automatically
Use the bullet gem in development:
# Gemfile
gem 'bullet'
# config/environments/development.rb
config.after_initialize do
Bullet.enable = true
Bullet.alert = true
Bullet.console = true
end
It will warn you in real-time when you’re making N+1 mistakes.
🧠 Final Thoughts
We all have off days in interviews — but what really matters is how we respond. For me, this was a chance to sharpen my Rails skills and make sure I never miss this question again.
If you’re working with Active Record and associations, knowing how to avoid N+1 is essential. Bookmark this for the next time you’re optimizing your queries — or prepping for your own technical interview!
