The Rails Router Everything you need to know about the incredible routing system in Rails. - Akshay Khot

  • Move Preface
    Open Preface

    Preface

    Do you ever get the feeling that you know a topic is important and that you should know well, but you only understand it superficially? Ever since I got into Rails, I've had that feeling with the Rails router.

    Coming from ASP.NET, I knew the concept of routing and got comfortable with the router after reading the docs. However, at the back of my mind, I've always had that nagging feeling that I don't REALLY understand the complete picture. I could make the basic routes and resources to get by for the simple CRUD tasks, but whenever I wanted to do something complicated, I found myself fumbling in dark.

    Well, after over a year of fumbling and trying to skim the docs and StackOverflow to just learn enough to get by, I decided to dig deeper and REALLY understand how Routing works in Rails.

    I've tried to summarize everything I learned in this handbook. It's more than 12,000 words, so don't expect to finish it in one sitting. However, i

    Preface 474 words
  • Move What is Routing?
    Open What is Routing?

    What is Routing?

    Before answering that, let me ask another question: What happens when someone visits your application? To keep things simple, let's ignore the load balancers, web servers, proxy servers, etc. and just assume the request directly hits your Rails application server.

    What happens when that request reaches your application?

    The very first thing that needs to happen is Rails needs to figure out which part of your codebase it should send (or route) that request to, so you can return a meaningful response to the browser. And here lies the answer to the question: What is Routing?

    In simple words,

    Routing is the process that determines what code in your application needs to run based on the URL of the incoming request.

    Router is one of the first components to run when an HTTP request hits your application. It inspects the incoming URL and directs it to the appropriate Ruby code. Typically, this code will be an action method inside a Rails controller.

    <p ali

    What is Routing? 373 words
  • Move The Rails Router
    Open The Rails Router

    The Rails Router

    In its essence, the routing system in Rails determines which code (specifically, an action method in a controller class) should be executed when the application receives an incoming HTTP request.

    But how does a router map incoming URLs to controller actions?

    First, you define the routes for your application in the config/routes.rb file. It's a plain Ruby file containing a specific domain specific language (DSL) that maps URL patterns to corresponding controller actions. The Rails router uses these rules to build out the routes and figure out where to direct the request.

    Each route in the routes file specifies a pattern that the router will use to match incoming URL and also to generate a URL. The route can contain dynamic segments as variable placeholders.

    Here's a simple route:

    # config/routes.rb
    
    get "courses/:title", to: "courses#show"
    

    This simple route consists of a few different components.

    1. get : HTTP verb

    2. courses/:title : UR

    The Rails Router 386 words
  • Move Router Configuration
    Open Router Configuration

    Router Configuration

    The config directory contains the configuration files for your Rails application. When you create a new Rails application, the application generator creates a config/routes.rb file which contains all the routes for your application. This gives a central place to look for all the paths and pages supported by your application.

    To configure the router, you add specific rules (called routes) in the routes.rb file. These routes tell the router how to map incoming URLs to specific controller actions.

    All the routes for your application live in the config/routes.rb file. Here's the default content of this file:

    Rails.application.routes.draw do
      get "up", to: "rails/health#show", as: :rails_health_check
    
      # Defines the root path route ("/")
      # root "posts#index"
    end
    

    It's a plain Ruby script. As you can see, it calls the draw method passing a block. The routes are configured inside the block.

    If you're not much familiar with Ruby, this configu

    Router Configuration 684 words
  • Move Digging Deeper: Router Internals
    Open Digging Deeper: Router Internals

    Digging Deeper: Router Internals

    In this section, we'll explore how Rails implements the beautiful routing DSL behind the scenes. This is going to be a bit technical, but nothing too complex, I promise.

    Let's revisit the config/routes.rb file we saw earlier.

    When you create a new Rails app, it automatically creates a /routes.rb file in the config directory. All it contains is a single call to the draw method on the object returned by the Rails.application.routes method. Additionally, it takes a block containing the routes for your application.

    Rails.application.routes.draw do
      # application routes go here...
    end
    

    To understand how the above method works, we need to take a short detour and understand Ruby's instance_exec method defined on the BasicObject class.


    Understanding How instance_exec Works

    The instance_exec method take

    Digging Deeper: Router Internals 696 words
  • Move Match Method
    Open Match Method

    Understanding the Match Method

    In this section, we will explore how the match method works behind the scenes. Once you really understand the match method and its options, the rest of the routing methods and shorthands become very easy to understand.

    The most basic way to define routes in Rails is to use the match method, which forms the core of the Router DSL. To 'really' understand the Rails Router API, it's essential to learn this method. All helper methods like get and post use match under the hood. Additionally, most of the shorthand syntax such as scopes and constraints use the options provided by match behind the scenes.

    For example, the following route instructs Rails to direct any POST request with the URL /posts/publish to the publish action method on the PostsController class.

    match "posts/publish/:id", controller: "posts", action: "publish", as: "publ
    
    Match Method 1,499 words
  • Move Dynamic Segment Keys
    Open Dynamic Segment Keys

    Dynamic Segment Keys

    You may have seen route paths such as posts/:id. If you're new to routing, you might be wondering why there are symbols inside the URL. These symbol-like terms are called segment keys, which make your URLs dynamic. In this lesson, we'll learn about the dynamic segment keys.

    Instead of hard-coding a URL which matches exactly one URL, segment keys allow you to match more than one URL. You can access the values of those keys in the params hash, e.g. params[:id].

    Consider this route:

    get "profile", to: "pages#profile"
    

    As you can guess, when the Rails application receives a request on the /profile page, it will direct that request to the profile method on the PagesController class.

    At the same time, Rails provides the controller and action name in a hash called params in the controller.

    # controllers/pages_controller.rb
    
    class PagesController < ApplicationController
      def profile
        puts params # {"controller"=>"pages", "ac
    
    Dynamic Segment Keys 735 words
  • Move Query Strings
    Open Query Strings

    Query Strings

    A query string is indicated by the first ? in the URL. It is used to pass additional data to the server.

    http://example.com/admin?true
    

    Rails allows you to handle query strings in a similar way to dynamic segments: by making them accessible in the params hash.

    Consider the following route:

    get 'photos/:id', to: 'photos#show'
    

    If the user agent sends an HTTP request to the photos/1?hue=10, the params hash will contain:

    params = {
      id: 1,
      hue: 10,
      # ...
    }
    

    In the next lesson, we'll learn about adding constraints to dynamic segments.


    If you have any questions or feedback, didn't understand something, or found a mistake, please leave a comment below or send me an email. You can also subscribe to my blog to receive future posts via email.

    Query Strings 138 words
  • Move Segment Constraints
    Open Segment Constraints

    Segment Constraints

    Sometimes you may want to add some constraints on the dynamic segments in a route. This is where the constraints option that we saw earlier, comes into the picture. You can add restrictions on the segment keys by providing a constraint.

    The following route matches only those URLs where slug is a word consisting of letters between a to z.

    get '/posts/:slug', to: 'posts#show', constraints: { slug: /[a-z]+/ }
    
    # or you can also use a shorthand
    get '/posts/:slug', to: 'posts#show', slug: /[a-z]+/
    

    Here's another example: you may want to restrict the id to three digits. For this, you can pass the :constraint option as follows:

    get 'images/:id', to: 'images#show', constraints: { id: /\d{3}/ }
    

    This route would match paths such as /images/293, but not /images/xyz.

    The above route can be succinctly expressed by passing the segment key itself.

    get 'photos/:id', to: 'photos#show', id: /\d{3}/
    

    Custom Constrain

    Segment Constraints 323 words
  • Move Named Routes
    Open Named Routes

    Named Routes

    So far, we have seen only one responsibility of the router: to match an incoming HTTP request to a route defined in the routes.rb file and route it to the piece of code that handles it, which is a corresponding action method on a controller class.

    • Input: HTTP Request URL
    • Output: Controller and Action

    Rails Router: From URL to Controller Action

    However, the Rails router also works in the other way. That is, given the controller and action, it can generate the URL for that route.

    • Input: Controller and Action
    • Output: HTTP Request URL

    Rails Router: From Controller Action to URL

    In addition, you can also name a route and use it to generate the matching URL. Given the route name (along wit

    Named Routes 833 words
  • Move Override ID Param
    Open Override ID Param

    How to Override the Named Route Parameter ID

    In the previous posts, we've learned about the concepts of dynamic segments as well as named routes in Rails. Naming a route generates two helper methods which can be used to generate the route URL, whereas a dynamic segment allows us to create dynamic routes, where the parts of the URL can vary.

    In this post, we'll combine these two concepts. Consider the following named route which contains a dynamic segment called :id:

    # config/routes.rb
    get "item/:id", to: "items#show", as: "item"
    

    When the application receives a request on /item/4, it forwards it to the ItemsController#show action. You can access the ID of the post as follows: params[:id].

    To generate the item URL, you can use the named route helper methods item_path and item_url, passing the ID of the post.

    item_path(id: @item.id) # /item/10
    

    In this example, @item is an instance of a Rails model.

    Typically, most of the time you'll work wi

    Override ID Param 764 words
  • Move Resourceful Routes
    Open Resourceful Routes

    Resourceful Routes

    Resourceful routing allows you to quickly declare all of the common routes for a given resource.

    The concept of resources is very powerful in Rails. With a single call to a method named resources, Rails will generate seven different routes for index, show, new, create, edit, update, and destroy actions, saving you a lot of typing.

    But saving a few keystrokes is just the cherry on top. The biggest benefit of using resourceful routing is that it provides a nice organizational structure for your Rails application, and helps you figure out how to name and organize the controller classes and action methods.

    Not only that, resourceful routing imposes certain constraints on your project which makes most Rails applications consistent and familiar. When a developer says that they have a post resource, another can safely assume (most of the time) that they have a PostController class with actions like create, show, edit, new, ... along with a Post model

    Resourceful Routes 1,619 words
  • Move Custom Routes
    Open Custom Routes

    Non-Resourceful Custom Routes

    A single call to resources in the routes.rb file declares the seven standard routes for your resource. **What if you need additional routes?*

    As we saw in the previous lesson, resourceful routes in Rails provide you with a nice set of named routes which are mapped to the common, standardized URL patterns. However, there might be situations when you want to veer off the beaten path and create custom routes in addition to the RESTful ones.

    Don't worry, Rails will let you create custom routes that don't fit one of the above seven routes with the member and collection routes. The member route only applies to a single resource, whereas collection will apply to a group of resources.

    But first, do you really need them at all?

    Before you continue, keep in mind that a better alternative to adding custom, non-resourceful routes is to introduce a new resourceful controller. Not only this keeps your code clean, but gives you better domain model.

    Here'

    Custom Routes 720 words
  • Move Nested Resources
    Open Nested Resources

    Nested Resources

    Imagine you're building a course platform, where each course has multiple lessons.

    • Each lesson is associated with a particular course.
    • Whenever you perform an operation on a lesson (create, read, update, delete), you're working in the context of an existing course.
    • When working with a lesson, you're really working with a course-lesson pair.

    Basically, the lesson resource is nested under the course resource.

    In a Rails routing file, you can represent the relationship between a course and its lessons as follows:

    # config/routes.rb
    resources :courses do
      resources :lessons
    end
    

    This instructs the Rails router to generate regular resourceful routes for the course resource, and generate nested, resourceful routes for the lesson resource.

    Let's check the routes generated for the lesson resource.

    $ bin/rails routes -g lesson
                    Prefix Verb   URI Pattern                                    Controller#Action
    
    
    Nested Resources 512 words
  • Move Shallow Nested Routes
    Open Shallow Nested Routes

    Shallow Nested Routes

    In the previous post, we learned how nested resources work. Consider the following route configuration:

    # config/routes.rb
    resources :courses do
      resources :lessons
    end
    

    It generates the following routes:

    $ bin/rails routes -g lesson
                    Prefix Verb   URI Pattern                                    Controller#Action
            course_lessons GET    /courses/:course_id/lessons(.:format)          lessons#index
                           POST   /courses/:course_id/lessons(.:format)          lessons#create
         new_course_lesson GET    /courses/:course_id/lessons/new(.:format)      lessons#new
        edit_course_lesson GET    /courses/:course_id/lessons/:id/edit(.:format) lessons#edit
             course_lesson GET    /courses/:course_id/lessons/:id(.:format)      lessons#show
                           PATCH  /courses/:course_id/lessons/:id(.:format)      lessons#update
                           PUT    /courses/:course_id/lessons/:id(.:format)      less
    
    Shallow Nested Routes 380 words
  • Move Route to Rack
    Open Route to Rack

    Route an Incoming URL to a Rack Application in Rails

    TL;DR: You can route an incoming HTTP request to a valid Rack endpoint using the following syntax:

    match '/url', to: RackApp
    
    # OR
    
    mount RackApp, at: "/url"
    
    # OR
    
    mount RackApp => "/url"
    

    Let's dig in to learn why, what, and how.

    This post won't make much sense if you don't know what Rack interface (or protocol) is, what problem it's designed to solve, and what a Rack-compliant application looks like. This post is a good starting point.


    Why You Want to Route to a Rack App

    We know that the Rails router can send an incoming HTTP request to an action method on a controller class. For example, the following route dispatches the request to /profile to the profile action on the PagesController class.

    # config/routes.rb
    get "profile", to: "pages#profile"
    

    Sometimes, you may want to route a particular URL (or a se

    Route to Rack 1,226 words
  • Move Routing Concerns
    Open Routing Concerns

    Routing Concerns

    Sometimes, you have common routes that you want to reuse inside other resources and routes. For example, imagine that your application has two resources, photos and posts.

    # config/routes.rb
    
    resources :posts
    resources :photos
    

    Next, you decide that you want to allow users to add comments under both posts and photos. That means you'll want to nest comments under both resources as follows:

    # config/routes.rb
    
    resources :posts do
      resources :comments
    end
    
    resources :photos do
      resources :comments
    end
    

    This is simple enough. But, you can imagine this can get repetitive if you have few more 'commentable' resources, i.e. resources that can be commented.

    To avoid this repetition, Rails lets you to declare these common routes (concerns) to reuse inside other resources and routes. For this, you'll use the concern method as follows:

    # config/routes.rb
    
    concern :commentable do
      resources :comments
    end
    
    resources :p
    
    Routing Concerns 609 words
  • Move Root Route
    Open Root Route

    Add Home Page with a Root Route

    Your application's home page is one of the most important and highly trafficked page. This is the page many visitors will encounter the first time they visit your application.

    The root helper method configures the home page of your Rails app.

    Rails.application.routes.draw do
      # Defines the root path route ("/")
      root "application#home"
    end
    

    The root indicates the application URL '/', without any path, such as /users.

    The router parses the routes top-down and stops search as soon as it finds a matching route. Hence, it's recommended that you should put the root route at the top of the routes file. It is the most popular route which should be matched first.

    Since most visitors will be visiting the application by making a GET request to your application URL, the root route only handles and routes HTTP GET requests.

    You can also use the root helper inside a namespaces and scope.

    namespace :admin do
      root to: "admin
    
    Root Route 238 words
  • Move Redirects
    Open Redirects

    How to Redirect Requests

    The redirect helper method lets you redirect any path to another path or URL. For example, the following route redirects all the incoming requests on /images to /photos.

    get "/images", to: redirect("/photos")
    
    # OR
    
    get "/images" => redirect("/photos")
    

    If the older route contained dynamic segments, you can reuse them with interpolation, as follows:

    get "/images/:tag", to: redirect("/photos/%{tag}")
    

    By default, the Rails router uses HTTP status 301 Moved Permanently for redirecting.

    The HyperText Transfer Protocol (HTTP) 301 Moved Permanently redirect status response code indicates that the requested resource has been definitively moved to the URL given by the [Location](https:

    Redirects 214 words
  • Move Resources: Where to Go From Here
    Open Resources: Where to Go From Here

    Resources: Where to Go From Here

    Thanks for reading this handbook. I hope you enjoyed reading it and have learned a thing or two about the Rails Router.

    If you want to learn more about routing, here're some additional resources.

    If you'd like to stay in touch, please subscribe my blog Write Software, Well.

    Resources: Where to Go From Here 92 words