How to Use includes in Rails for Efficient Queries
In Rails, use
includes to preload associated records and avoid N+1 query problems. It loads related data in fewer queries, improving performance when accessing associations.Syntax
The includes method is called on an ActiveRecord query to preload associations. It takes one or more association names as symbols or arrays.
Model.includes(:association)loads the specified association.- You can pass multiple associations like
includes(:assoc1, :assoc2). - It returns an ActiveRecord::Relation that fetches associated records efficiently.
ruby
Model.includes(:association_name)Example
This example shows how to use includes to preload comments when fetching posts, avoiding extra queries when accessing comments.
ruby
class Post < ApplicationRecord has_many :comments end class Comment < ApplicationRecord belongs_to :post end # Fetch posts with comments preloaded def fetch_posts_with_comments posts = Post.includes(:comments).limit(3) posts.each do |post| puts "Post: #{post.title}" post.comments.each do |comment| puts "- Comment: #{comment.body}" end end end fetch_posts_with_comments
Output
Post: First Post
- Comment: Great post!
- Comment: Thanks for sharing.
Post: Second Post
- Comment: Interesting read.
Post: Third Post
- Comment: Nice article.
Common Pitfalls
Common mistakes when using includes include:
- Using
includesbut then filtering on the included association in a way that triggers extra queries (usereferencesorjoinsfor conditions). - Expecting
includesto always eager load; sometimes Rails falls back to lazy loading if conditions are not met. - Not using
includeswhen accessing associations in loops, causing N+1 queries.
ruby
# Wrong: causes N+1 queries posts = Post.all posts.each do |post| puts post.comments.count end # Right: preloads comments to avoid N+1 posts = Post.includes(:comments).all posts.each do |post| puts post.comments.count end
Quick Reference
| Usage | Description |
|---|---|
| Model.includes(:assoc) | Preloads the association to avoid N+1 queries |
| Model.includes(:assoc1, :assoc2) | Preloads multiple associations |
| Model.includes(:assoc).where(assoc: { attr: value }) | Use with references or joins for conditions on associations |
| Model.joins(:assoc) | Joins tables but does not preload associations |
| Model.eager_load(:assoc) | Forces eager loading with LEFT OUTER JOIN |
Key Takeaways
Use includes to preload associations and avoid N+1 query problems.
Pass association names as symbols to includes for efficient loading.
Combine includes with references or joins when filtering on associations.
Without includes, accessing associations in loops causes many extra queries.
Check query logs to confirm includes is working as expected.