Ruby
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax
-
Section 3: Methods and Blocks
-
Section 4: Object-Oriented Ruby
-
Section 5: Metaprogramming
-
Section 6: Working with Data and Files
-
Section 7: Ruby Frameworks Overview
-
Section 8: Ecosystem and Testing
-
Section 9: Practical Projects
-
Section 10: Interview Practice
-
Section 11: Data Structures and Algorithms in Ruby
-
Section 12: More Practice Exercises
-
Section 13: Enumerable and Functional Style
-
Section 14: More OOP Practice
-
Section 15: More Testing
-
Section 16: Enumerable and Comparable Modules In Depth
-
Section 17: Ruby Standard Library: Core Utilities
-
Section 18: Ruby Standard Library: Data and Security
-
Section 19: Ruby Standard Library: CLI and Text
-
Section 20: Ruby Networking
-
Section 21: Ruby on Rails Deep Dive
-
Section 22: Ruby Metaprogramming Deep Dive
-
Section 23: Ruby Design Patterns
-
Section 24: Ruby Concurrency
-
Section 25: Ruby Testing Deep Dive
-
Section 26: Ruby Gems and Packaging
-
Section 27: Ruby Performance
-
Section 28: More Practice Exercises
-
Section 29: More Interview Practice
-
Section 30: Rails API Development
-
Section 31: Rails Authentication and Authorization
-
Section 32: Rails Testing Deep Dive
-
Section 33: Rails Performance
-
Section 34: Rails Deployment
-
Section 35: Sinatra and Lightweight Ruby Web Apps
-
Section 36: More Ruby Language Deep Dive
-
Section 37: Ruby 3.x Modern Features
-
Section 38: More Data Structures in Ruby
-
Section 39: More Practical Projects
-
Section 40: Ruby Ecosystem Tools
-
Section 41: More Practice and Review
-
Section 42: Final Practice and Mastery
-
Section 43: Ruby Interview Deep Dive
-
Section 44: Ruby Background Processing Deep Dive
-
Section 45: Ruby GraphQL
-
Section 46: Ruby Object Model Deep Dive
-
Section 47: Ruby Hanami Framework Overview
-
Section 48: Ruby gRPC and Protocol Buffers
-
Section 49: Ruby Data Processing
-
Section 50: Ruby Search Integration
-
Section 51: Ruby File Upload and Media
-
Section 52: Ruby Email and Notifications
-
Section 53: Ruby Admin Panels
-
Section 54: Ruby Feature Flags and Experimentation
-
Section 55: Ruby Monitoring and Observability
-
Section 56: Ruby Docker and Deployment Deep Dive
-
Section 57: Ruby Security Deep Dive
-
Section 58: More Advanced Metaprogramming
-
Section 59: More Final Projects
137: Database Indexing for Rails Apps
Imagine you're holding a 1,000-page technical manual on jet engines. You need to find the specific section on "Fuel Injector Calibration." You have two choices: you can start at page one and read every single sentence until you hit that phrase, or you can flip to the index at the back, find "Fuel Injector," see that it's on page 412, and jump straight there.
In database terms, reading every page is called a Full Table Scan. It's fine when your table has ten rows, but when you have ten million, your app will essentially freeze while the database grinds through every single record. The index at the back of the book is exactly what a database index is—a separate, sorted data structure that tells the database exactly where the row lives on the disk so it can skip the line.
Teaching Rails to Shortcut the Search
Most of the time, you'll be indexing columns that you use frequently in where clauses. Let's say you have a User model and you're looking up users by their email address during login. Without an index, Postgres or MySQL has to check every single user record to find the match.
You handle this in Rails via a migration. I've seen a lot of developers forget this step, only to realize their app is crawling in production. Here is how you'd add a standard index to the email column:
class AddIndexToUsersEmail
Notice I added unique: true. This is a pro move. Not only does it speed up the search, but it creates a database-level constraint that prevents two users from ever having the same email, even if your Rails validations somehow fail during a race condition.
Handling Multiple Columns Together
Sometimes, you aren't searching by just one thing. Imagine you're building a dashboard that shows Orders filtered by both user_id and status. If you have separate indexes on both, the database has to pick one, filter the results, and then manually sift through those for the second criteria.
A composite index allows the database to look for the combination of both values simultaneously. Order matters here—the database can use the index for the first column alone, or the first and second together, but it can't use it for the second column alone.
class AddCompositeIndexToOrders
I usually suggest putting the column with the highest "cardinality" (the one with the most unique values, like user_id) first in the array.
The Hidden Cost of Over-Indexing
It's tempting to just index every single column "just in case." Don't do that. Every time you INSERT or UPDATE a record, the database has to update the index as well. If you have ten indexes on one table, a single write operation suddenly becomes eleven write operations. You're trading write speed for read speed.
My rule of thumb? Index your foreign keys (Rails doesn't always do this automatically depending on how you write your references) and any column that appears in a where or order clause in your most-hit controllers. If you're unsure, use a tool like rack-mini-profiler or check your logs for "Slow Queries."
📋 Practical Task
Optimizing the Order History Search
You are working on a legacy Rails app where the Order table has grown to 500,000 rows. The "My Orders" page is taking 3 seconds to load because it executes this query: Order.where(user_id: current_user.id, status: 'shipped').order(created_at: :desc).
Currently, there is an index on user_id, but the database is still struggling to filter by status and sort by date.
Your Task: Generate and write a migration that adds a composite index to the orders table. This index should optimize the query by covering the user_id, the status, and the created_at timestamp in a single index. Ensure the columns are ordered logically to support the filtering and the sorting.
There are no comments for now.