Skip to Content
Course content

84: Rails Routing In Depth

Click on the "Edit" button in the top corner of the screen to edit your slide content.

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 PATCH request. The URL should look like /projects/:id/archive.
  • Project Search: Create a route that allows users to search through all projects using a GET request. 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 PUT request. 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.

Rating
0 0

There are no comments for now.

to be the first to leave a comment.