DEV Community

Cover image for Rails Routes - Mastering Routing in Ruby on Rails: A Concise Guide with Code Examples
LUIS CUEVAS
LUIS CUEVAS

Posted on

Rails Routes - Mastering Routing in Ruby on Rails: A Concise Guide with Code Examples

1. Single Route Resources

Single route resources are a straightforward way to define routes for a resource with only one route. Let's create a route for a "book" resource using Rails resources method:

# config/routes.rb
resources :books, only: [:show]
Enter fullscreen mode Exit fullscreen mode

In this example, we've defined a single "show" route for the "books" resource, which maps to the "BooksController#show" action.
But if we want all the whole REST routes for books, we use this.

resources :books
Enter fullscreen mode Exit fullscreen mode

2. Nested Routes

Nested routes in Ruby on Rails involve physically nesting one resource inside a block supplied to another resource in the routes file. This allows for URLs like '/books/2/chapters/10', where chapters are nested under books.

Nested routes allow you to express hierarchical relationships between resources. For instance, if you have a 'Chapter' resource that belongs to a 'Book,' you can set up nested routes like this:

resources :books do
  resources :chapters
end
Enter fullscreen mode Exit fullscreen mode

of course we have defined associations between models

# app/models/book.rb
class Book < ApplicationRecord
  has_many :chapters
end
Enter fullscreen mode Exit fullscreen mode

and

# app/models/chapter.rb
class Chapter < ApplicationRecord
  belongs_to :book
end
Enter fullscreen mode Exit fullscreen mode

3. Member and Collection Routes

In Ruby on Rails, when defining routes for a resource, you have the flexibility to add custom actions using member and collection routes. These two types of routes serve different purposes and are suitable for distinct scenarios.

Suppose you have a "books" resource and want to add a custom "highlight" action for a specific book. You can define a member route like this:

resources :books do
  member do
    get 'highlight'
  end
end

Enter fullscreen mode Exit fullscreen mode

Now, you can access the "highlight" action for a specific book using a URL like "/books/1/highlight," where "1" represents the book's ID.

Suppose you want to add a custom "search" action that searches for books across the entire collection. You can define a collection route like this:

resources :books do
  collection do
    get 'search'
  end
end
Enter fullscreen mode Exit fullscreen mode

Now, you can perform a search action that applies to all books using a URL like "/books/search."

Note that Member routes typically map to actions that perform operations on a single member or instance of a resource.
Collection routes map to actions that involve the entire collection of a resource.

4. Adding Non-RESTful Routes

Sometimes, you may need routes that don't follow RESTful conventions. For example, let's create a custom route for marking a book as a favorite:

# config/routes.rb
resources :books do
  post 'favorite', on: :member
end
Enter fullscreen mode Exit fullscreen mode

Below are other different approaches to implement a non-RESTful route for this scenario:

Using the match Method

This approach allows you to specify the HTTP method (e.g., POST) and the controller action to be invoked. The :as option allows you to create a named route helper method, such as favorite_book_path, for generating URLs to this route.

match '/books/:id/favorite', to: 'books#favorite', via: :post, as: :favorite_book
Enter fullscreen mode Exit fullscreen mode

Using post Method with on: Option

By specifying the on: option within the post method in your routes file. This approach explicitly states that the "favorite" route is a member route, and it maps to the favorite action in the BooksController

resources :books do
  post 'favorite', on: :member, to: 'books#favorite'
end
Enter fullscreen mode Exit fullscreen mode

Using Custom Named Routes

With this approach, you have flexibility in naming the route and can use the generated named route helper (e.g., mark_favorite_path or custom_favorite_route_path) to generate URLs for this non-RESTful action.

post '/books/:id/favorite', to: 'books#favorite', as: :mark_favorite

# OR, using a custom helper method name
post '/books/:id/favorite', to: 'books#favorite', as: :custom_favorite_route

Enter fullscreen mode Exit fullscreen mode

Now, you can mark a book as a favorite by making a POST request to "/books/1/favorite."

5. Redirects

In Rails, you can define redirects easily in your routes file. Suppose you want to redirect "/old_path" to "/new_path":

# config/routes.rb
get '/old_path', to: redirect('/new_path')
Enter fullscreen mode Exit fullscreen mode

This code will redirect any request to "/old_path" to "/new_path."

6. Wildcard Routes

Wildcard routes are a powerful tool for handling dynamic URLs. Suppose you want to capture all requests to "/books/*" and route them to a specific controller action:

get '/books/*path', to: 'books#show'
Enter fullscreen mode Exit fullscreen mode

With this wildcard route, you can capture various book-related paths and route them to the "BooksController#show" action.

7. Some Anti-Patterns, or Please Dont

Overuse of Custom Routes

Anti-Pattern: Defining excessive custom routes for every controller action

resources :books do
  get 'custom_action_1', on: :member
  post 'custom_action_2', on: :collection
  put 'custom_action_3', on: :member
  # ... more custom actions ...
end
Enter fullscreen mode Exit fullscreen mode

Instead, it's recommended to use RESTful routes whenever possible and resort to custom routes only when necessary.

Verbosity in Named Routes:

Anti-Pattern: Using overly verbose names for named routes.

# BAD
get '/books/:id/edit_book', to: 'books#edit', as: :edit_book_action

# GOOD
get '/books/:id/edit', to: 'books#edit', as: :edit_book
Enter fullscreen mode Exit fullscreen mode

Unused or Dead Routes

Anti-Pattern: Defining routes that are no longer used in the application.

get '/unused_route', to: 'unused#action'

Enter fullscreen mode Exit fullscreen mode

Such routes should be removed to maintain a clean and maintainable route configuration

Complex Route Constraints

Anti-Pattern: Overcomplicating routes with complex constraints.

get '/books/:id', to: 'books#show', constraints: { id: /\d{3}/ }
Enter fullscreen mode Exit fullscreen mode

Keep route constraints simple and understandable, and use them sparingly.

Lack of RESTful Structure with RESTful actions

Anti-Pattern: Creating routes that don't adhere to RESTful principles when these are for RESTful action in the first place.

# BAD because show is a RESTful action
get '/books/show_book/:id', to: 'books#show'
# Better
resources :books, only: [:show]
Enter fullscreen mode Exit fullscreen mode

Inconsistent Route Naming

Anti-Pattern: Using inconsistent naming conventions for routes.

# Wrong
get '/books/show_book/:id', to: 'books#show', as: :display_single_book
# Best
resources :books, only: [:show]
Enter fullscreen mode Exit fullscreen mode

Consistency in naming conventions makes the codebase more understandable

By avoiding these anti-patterns and following Rails' conventions for routing definitions, you can maintain a clean and maintainable routing configuration in your Ruby on Rails application, making it easier for developers to understand and work with the code.

Conclusion:

Mastering routing in Ruby on Rails is essential for building robust web applications. In this concise guide, we've covered single route resources, nested routes, member and collection routes, non-RESTful routes, redirects, and wildcard routes, and anti-patterns, each of these illustrated with code examples. By understanding these routing concepts, you'll be better equipped to handle complex routing scenarios in your Rails applications.

Top comments (0)