Bird
Raised Fist0
Ruby on Railsframework~8 mins

Joins and includes in Ruby on Rails - Performance & Optimization

Choose your learning style10 modes available
Performance: Joins and includes
HIGH IMPACT
This concept affects how database queries load related data, impacting page load speed and interaction responsiveness.
Loading posts with their authors to display on a page
Ruby on Rails
posts = Post.includes(:author).all
posts.each do |post|
  puts post.author.name
end
Preloads all authors in a single query, reducing database calls and speeding up data retrieval.
📈 Performance GainSingle query for posts and authors combined, reducing queries from N+1 to 2.
Loading posts with their authors to display on a page
Ruby on Rails
posts = Post.all
posts.each do |post|
  puts post.author.name
end
This triggers an N+1 query problem, causing one query for posts plus one query per post to fetch the author.
📉 Performance CostTriggers N+1 queries, increasing database load and blocking rendering until all queries complete.
Performance Comparison
PatternDOM OperationsReflowsPaint CostVerdict
N+1 queries without includesN/AN/ABlocks rendering until all queries finish[X] Bad
Using includes to preload associationsN/AN/AFaster rendering due to fewer queries[OK] Good
Filtering with Ruby after loading all dataN/AN/AHigh memory and CPU usage delays rendering[X] Bad
Filtering with joins in SQLN/AN/AEfficient data retrieval speeds up rendering[OK] Good
Rendering Pipeline
Joins and includes affect the data fetching stage before rendering. Efficient queries reduce wait time before HTML can be generated and painted.
→Data Fetching
→Rendering
→Interaction Responsiveness
⚠️ BottleneckData Fetching (database queries)
Core Web Vital Affected
LCP
This concept affects how database queries load related data, impacting page load speed and interaction responsiveness.
Optimization Tips
1Avoid N+1 queries by using includes to preload associations.
2Use joins with where clauses to filter data at the database level.
3Filtering large datasets in Ruby after loading slows down rendering and increases memory use.
Performance Quiz - 3 Questions
Test your performance knowledge
What is the main performance problem with using Post.all and then accessing post.author.name in a loop?
AIt causes N+1 database queries, slowing down page load
BIt uses too much memory on the client side
CIt triggers multiple reflows in the browser
DIt increases CSS selector complexity
DevTools: Network and Performance panels
How to check: Open DevTools, go to Network tab, reload page and observe number of API/database calls; then use Performance tab to see blocking time.
What to look for: Look for multiple similar queries (N+1 problem) in Network; long blocking times in Performance indicate slow data fetching.

Practice

(1/5)
1. What is the main purpose of using joins in Rails ActiveRecord queries?
easy
A. To update multiple tables at once
B. To preload associated records to avoid extra database queries
C. To combine tables and filter records based on matching columns
D. To delete records from multiple tables

Solution

  1. Step 1: Understand what joins does

    joins connects tables in a query to filter or find records that match conditions across those tables.
  2. Step 2: Compare with includes

    includes is used to preload associated data to reduce queries, not for filtering.
  3. Final Answer:

    To combine tables and filter records based on matching columns -> Option C
  4. Quick Check:

    joins = combine tables for filtering [OK]
Hint: Remember: joins filters by matching tables, includes preloads data [OK]
Common Mistakes:
  • Confusing joins with includes
  • Thinking joins preload data
  • Assuming joins update or delete records
2. Which of the following is the correct syntax to use includes to preload the comments association on a Post model?
easy
A. Post.includes('comments').where(published: true)
B. Post.includes(:comments).where(published: true)
C. Post.include(:comments).where(published: true)
D. Post.joins(:comments).includes.where(published: true)

Solution

  1. Step 1: Check the correct method name and argument type

    The method is includes (plural), and it accepts a symbol like :comments.
  2. Step 2: Validate the chaining and syntax

    Post.includes(:comments).where(published: true) uses Post.includes(:comments).where(published: true), which is correct syntax to preload comments and filter posts.
  3. Final Answer:

    Post.includes(:comments).where(published: true) -> Option B
  4. Quick Check:

    Correct method and symbol argument = Post.includes(:comments).where(published: true) [OK]
Hint: Use plural includes with symbol for associations [OK]
Common Mistakes:
  • Using singular include instead of includes
  • Passing association as string instead of symbol
  • Chaining includes incorrectly
3. Given these models: Author has_many :books and Book belongs_to :author, what will this query return?
Author.joins(:books).where(books: { published: true }).distinct
medium
A. All authors with all their books loaded
B. All books that are published
C. All authors including those without books
D. All authors who have at least one published book

Solution

  1. Step 1: Analyze the joins and where clause

    The query joins authors with books and filters books where published: true.
  2. Step 2: Understand the effect of distinct

    distinct ensures authors are unique even if they have multiple published books.
  3. Final Answer:

    All authors who have at least one published book -> Option D
  4. Quick Check:

    joins + where filters authors by published books [OK]
Hint: joins filters parents by child conditions; distinct avoids duplicates [OK]
Common Mistakes:
  • Thinking it returns books instead of authors
  • Assuming includes loads all books
  • Ignoring distinct causing duplicates
4. Identify the error in this Rails query:
Post.joins(:comments).includes(:author).where(comments: { approved: true })
medium
A. No error; the query is valid and will work as expected
B. The where clause should reference authors instead of comments
C. Using both joins and includes together causes a syntax error
D. The includes should come before joins to avoid errors

Solution

  1. Step 1: Check if using joins and includes together is allowed

    Rails allows chaining joins and includes to combine filtering and eager loading.
  2. Step 2: Verify the where clause references a valid table

    The where filters on comments which is joined, so it's valid.
  3. Final Answer:

    No error; the query is valid and will work as expected -> Option A
  4. Quick Check:

    joins + includes + where on joined table = valid [OK]
Hint: joins and includes can be chained; where must match joined tables [OK]
Common Mistakes:
  • Thinking joins and includes can't be combined
  • Confusing which table to filter in where
  • Assuming order of joins/includes causes errors
5. You want to fetch all Order records with their associated Customer and OrderItems, but only include orders where the customer is active and at least one order item is in stock. Which query correctly uses joins and includes to achieve this efficiently?
hard
A. Order.joins(:customer, :order_items).includes(:customer, :order_items).where(customers: { active: true }, order_items: { in_stock: true }).distinct
B. Order.includes(:customer, :order_items).where(customers: { active: true }, order_items: { in_stock: true })
C. Order.joins(:customer).includes(:order_items).where(customers: { active: true }).where(order_items: { in_stock: true })
D. Order.joins(:customer).joins(:order_items).where(customers: { active: true }, order_items: { in_stock: true })

Solution

  1. Step 1: Understand filtering and eager loading needs

    We must filter orders by customer active status and order items in stock, so joins is needed to filter across tables.
  2. Step 2: Use includes to preload associations for efficient access

    To avoid N+1 queries when accessing customers and order items, includes preloads them.
  3. Step 3: Use distinct to avoid duplicate orders from multiple matching order items

    Because joins can cause duplicates, distinct ensures unique orders.
  4. Final Answer:

    Order.joins(:customer, :order_items).includes(:customer, :order_items).where(customers: { active: true }, order_items: { in_stock: true }).distinct -> Option A
  5. Quick Check:

    joins filters, includes preloads, distinct removes duplicates [OK]
Hint: Use joins to filter, includes to preload, distinct to avoid duplicates [OK]
Common Mistakes:
  • Using only includes without joins for filtering
  • Not using distinct causing duplicate records
  • Mixing joins and includes incorrectly
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard