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
84: Rails Routing In Depth
Imagine you're calling a massive corporate headquarters. You don't just magically appear in the CEO's office the moment you dial the main number. Instead, you hit a switchboard. The operator asks, "Who are you trying to reach?" and "What is the purpose of your call?" If you say you want to "Pay a Bill" (the intent/verb) in the "Accounting Department" (the path), the operator patches you through to a specific clerk who knows exactly how to handle payments. If you ask to "Update your Address" in the "HR Department," you get sent to a different person entirely.
In Rails, routes.rb is that switchboard operator. It takes an incoming HTTP request—which consists of a URL and a Verb (GET, POST, PATCH, DELETE)—and decides which Controller and which Action should handle the heavy lifting. If you get this wrong, your app is basically a building with no doors.
The Efficiency of Resourceful Routing
By now, you've probably used resources :photos. It feels like magic because one line generates seven different routes. But as a pro, you need to stop seeing it as magic and start seeing it as a convention. Rails assumes that if you have a "Photo" resource, you'll want to do the standard CRUD operations: index, show, new, create, edit, update, and destroy.
I've seen developers try to manually write out every single route for every controller. Please, don't do that. It's a maintenance nightmare. Stick to the resourceful pattern unless you have a very specific reason not to.
Dealing with the "In-Between" Actions
Eventually, you'll hit a wall where a standard CRUD action doesn't fit. Let's say we're building a Project Management app. You have a Project resource, but you need a way to "Archive" a project. Archiving isn't exactly "updating" the whole record, and it's definitely not "destroying" it. This is where member and collection blocks come in.
resources :projects do
member do
patch :archive # This acts on a SPECIFIC project (e.g., /projects/5/archive)
end
collection do
get :search # This acts on the WHOLE group (e.g., /projects/search)
end
end
Here is the rule of thumb I use: If the URL needs an ID (like /projects/5/archive), it's a member route. If the URL describes a general action for the whole group (like /projects/search), it's a collection route. If you swap these, Rails will throw a routing error because it'll be looking for an ID that isn't there, or ignoring an ID that is.
Adding Context through Nesting
Now, projects have tasks. A task doesn't really exist in a vacuum; it belongs to a project. You could just do resources :tasks, but then your URLs look like /tasks/12. That's fine, but it doesn't tell the story of the data. Nesting allows you to reflect the relationship in the URL.
resources :projects do
resources :tasks
end
Now, to see a task, you go to /projects/5/tasks/12. This tells the controller exactly which project context the task belongs to. Just a word of caution: don't nest more than one level deep. If you find yourself writing /projects/5/tasks/12/comments/3/likes/1, you've gone too far. At that point, just pull the deepest resource out into its own top-level route. Your URLs will be shorter, and your sanity will remain intact.
Constraining the Switchboard
Sometimes you want to be picky about who gets through. Maybe you only want a route to work if the ID is a number, or if the request comes from a specific subdomain. You can use constraints for this. It keeps your controller cleaner because the request never even hits the controller if the constraint fails.
get 'profile/:username', to: 'users#show', constraints: { username: /[a-zA-Z0-9_]+/ }
In this example, if someone tries to put symbols or spaces in the username URL, Rails will act like the route doesn't even exist (returning a 404) rather than sending a weird string to your User controller and risking a database error.
📋 Practical Task
Implementing Advanced Routes for a Project Management Suite
You are working on a Project Management application. Currently, you have basic resourceful routing for projects and tasks (nested under projects). You need to implement the following specific requirements in your config/routes.rb file:
- Project Archiving: Create a route that allows a specific project to be archived using a
PATCHrequest. The URL should look like/projects/:id/archive. - Project Search: Create a route that allows users to search through all projects using a
GETrequest. The URL should be/projects/search. - Task Prioritization: Tasks are nested under projects. Create a member route for tasks that allows a specific task to be marked as "high priority" using a
PUTrequest. The URL should look like/projects/:project_id/tasks/:id/prioritize.
Write the routes.rb code that implements these three specific requirements while maintaining the standard resourceful routing for both projects and tasks.
There are no comments for now.