Joins and includes help you get related data from the database efficiently. They make your app faster and avoid repeating queries.
Joins and includes in Ruby on Rails
Model.joins(:association) Model.includes(:association)
joins creates an SQL INNER JOIN and returns records matching the join condition.
includes loads associated records in advance to avoid extra queries (eager loading).
Post.joins(:comments)
Post.includes(:comments)
Post.joins(:comments).where(comments: { approved: true })Post.includes(:comments).where(title: 'Hello')This example shows how to use joins to get posts that have comments and includes to load posts with their comments efficiently. It prints post titles from the join and shows how many comments each post has when using includes.
class Post < ApplicationRecord has_many :comments end class Comment < ApplicationRecord belongs_to :post end # Get posts with comments using joins posts_with_comments = Post.joins(:comments).distinct # Get posts and load comments to avoid extra queries posts_with_includes = Post.includes(:comments).limit(2) # Print results puts "Posts with comments (joins):" posts_with_comments.each { |p| puts p.title } puts "\nPosts with comments loaded (includes):" posts_with_includes.each do |p| puts "#{p.title} has #{p.comments.size} comments" end
Use joins when you want to filter or match records based on related tables.
Use includes to avoid the N+1 query problem by loading related data in advance.
joins returns only records with matching associations; includes returns all records and loads associations separately.
joins connects tables to filter or find matching records.
includes loads related data ahead to speed up access.
Both help your app get related data efficiently and avoid slow database calls.
Practice
joins in Rails ActiveRecord queries?Solution
Step 1: Understand what
joinsdoesjoinsconnects tables in a query to filter or find records that match conditions across those tables.Step 2: Compare with
includesincludesis used to preload associated data to reduce queries, not for filtering.Final Answer:
To combine tables and filter records based on matching columns -> Option CQuick Check:
joins= combine tables for filtering [OK]
- Confusing joins with includes
- Thinking joins preload data
- Assuming joins update or delete records
includes to preload the comments association on a Post model?Solution
Step 1: Check the correct method name and argument type
The method isincludes(plural), and it accepts a symbol like:comments.Step 2: Validate the chaining and syntax
Post.includes(:comments).where(published: true) usesPost.includes(:comments).where(published: true), which is correct syntax to preload comments and filter posts.Final Answer:
Post.includes(:comments).where(published: true) -> Option BQuick Check:
Correct method and symbol argument = Post.includes(:comments).where(published: true) [OK]
- Using singular include instead of includes
- Passing association as string instead of symbol
- Chaining includes incorrectly
Author has_many :books and Book belongs_to :author, what will this query return?Author.joins(:books).where(books: { published: true }).distinctSolution
Step 1: Analyze the
The query joins authors with books and filters books wherejoinsandwhereclausepublished: true.Step 2: Understand the effect of
distinctdistinctensures authors are unique even if they have multiple published books.Final Answer:
All authors who have at least one published book -> Option DQuick Check:
joins + where filters authors by published books [OK]
- Thinking it returns books instead of authors
- Assuming includes loads all books
- Ignoring distinct causing duplicates
Post.joins(:comments).includes(:author).where(comments: { approved: true })Solution
Step 1: Check if using
Rails allows chainingjoinsandincludestogether is allowedjoinsandincludesto combine filtering and eager loading.Step 2: Verify the
Thewhereclause references a valid tablewherefilters oncommentswhich is joined, so it's valid.Final Answer:
No error; the query is valid and will work as expected -> Option AQuick Check:
joins + includes + where on joined table = valid [OK]
- Thinking joins and includes can't be combined
- Confusing which table to filter in where
- Assuming order of joins/includes causes errors
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?Solution
Step 1: Understand filtering and eager loading needs
We must filter orders by customer active status and order items in stock, sojoinsis needed to filter across tables.Step 2: Use
To avoid N+1 queries when accessing customers and order items,includesto preload associations for efficient accessincludespreloads them.Step 3: Use
Because joins can cause duplicates,distinctto avoid duplicate orders from multiple matching order itemsdistinctensures unique orders.Final Answer:
Order.joins(:customer, :order_items).includes(:customer, :order_items).where(customers: { active: true }, order_items: { in_stock: true }).distinct -> Option AQuick Check:
joins filters, includes preloads, distinct removes duplicates [OK]
- Using only includes without joins for filtering
- Not using distinct causing duplicate records
- Mixing joins and includes incorrectly
Ready to prove it?
Pass the test and this pattern moves unknown
