CINXE.COM
Rails Routing from the Outside In — Ruby on Rails Guides
<!doctype html> <html dir="ltr" lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>Rails Routing from the Outside In — Ruby on Rails Guides</title> <link rel="stylesheet" type="text/css" href="stylesheets/style-071e355820fc155a5c40ef8a1c0c4971.css" data-turbo-track="reload"> <link rel="stylesheet" type="text/css" href="stylesheets/print-a87ee66d50ce96bb83ac082f1249fe3e.css" media="print"> <link rel="stylesheet" type="text/css" href="stylesheets/highlight-a0d2133dd0073968b2d33b1f1360a2a3.css" data-turbo-track="reload"> <link rel="icon" href="images/favicon.ico" sizes="any"> <link rel="apple-touch-icon" href="images/icon.png"> <script src="javascripts/@hotwired--turbo-764f59c7edbeb902a9068c0340dd274e.js" data-turbo-track="reload"></script> <script src="javascripts/clipboard-8b7aed6f069f0cf58eeae353cd2f898b.js" data-turbo-track="reload"></script> <script src="javascripts/guides-897790ae3777ddd81bd4953f7ec99835.js" data-turbo-track="reload"></script> <meta property="og:title" content="Rails Routing from the Outside In — Ruby on Rails Guides" /> <meta name="description" content="Rails Routing from the Outside InThis guide covers the user-facing features of Rails routing.After reading this guide, you will know: How to interpret the code in config/routes.rb. How to construct your own routes, using either the preferred resourceful style or the match method. How to declare route parameters, which are passed onto controller actions. How to automatically create paths and URLs using route helpers. Advanced techniques such as creating constraints and mounting Rack endpoints." /> <meta property="og:description" content="Rails Routing from the Outside InThis guide covers the user-facing features of Rails routing.After reading this guide, you will know: How to interpret the code in config/routes.rb. How to construct your own routes, using either the preferred resourceful style or the match method. How to declare route parameters, which are passed onto controller actions. How to automatically create paths and URLs using route helpers. Advanced techniques such as creating constraints and mounting Rack endpoints." /> <meta property="og:locale" content="en_US" /> <meta property="og:site_name" content="Ruby on Rails Guides" /> <meta property="og:image" content="https://avatars.githubusercontent.com/u/4223" /> <meta property="og:type" content="website" /> <link rel="preconnect" href="https://fonts.googleapis.com"> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin> <link href="https://fonts.googleapis.com/css2?family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css2?family=Heebo:wght@100..900&family=Noto+Sans+Arabic:wght@100..900&display=swap" rel="stylesheet"> <meta name="theme-color" content="#C81418"> </head> <body dir="ltr" class="guide no-js"> <script> document.body.classList.remove('no-js') </script> <a id="main-skip-link" href="#main" class="skip-link" data-turbo="false"> Skip to main content </a> <div id="mobile-navigation-bar"> <div class="wrapper"> <strong class="more-info-label">More at <a href="https://rubyonrails.org/">rubyonrails.org:</a> </strong> <button type="button" class="js-only red-button more-info-button" id="more-info" aria-controls="more-info-links" aria-expanded="false"> More Ruby on Rails </button> <ul id="more-info-links" class="more-info-links hidden"> <li class="more-info"><a href="https://rubyonrails.org/blog">Blog</a></li> <li class="more-info"><a href="https://guides.rubyonrails.org/">Guides</a></li> <li class="more-info"><a href="https://api.rubyonrails.org/">API</a></li> <li class="more-info"><a href="https://discuss.rubyonrails.org/">Forum</a></li> <li class="more-info"><a href="https://github.com/rails/rails">Contribute on GitHub</a></li> </ul> </div> </div> <header id="page-header"> <div class="wrapper clearfix"> <nav id="feature-nav"> <div class="header-logo"> <a href="index.html" title="Guides home for v8.0.0 Guides">Guides</a> <span id="version-switcher" class="js-only"> <label for="version-switcher-select">Version: <span class="visibly-hidden">pick from the list to go to that Rails version's guides</span></label> <select id="version-switcher-select" class="guides-version"> <option value="https://edgeguides.rubyonrails.org/">Edge</option> <option value="https://guides.rubyonrails.org/v8.0/" selected>8.0</option> <option value="https://guides.rubyonrails.org/v7.2/">7.2</option> <option value="https://guides.rubyonrails.org/v7.1/">7.1</option> <option value="https://guides.rubyonrails.org/v7.0/">7.0</option> <option value="https://guides.rubyonrails.org/v6.1/">6.1</option> <option value="https://guides.rubyonrails.org/v6.0/">6.0</option> <option value="https://guides.rubyonrails.org/v5.2/">5.2</option> <option value="https://guides.rubyonrails.org/v5.1/">5.1</option> <option value="https://guides.rubyonrails.org/v5.0/">5.0</option> <option value="https://guides.rubyonrails.org/v4.2/">4.2</option> <option value="https://guides.rubyonrails.org/v4.1/">4.1</option> <option value="https://guides.rubyonrails.org/v4.0/">4.0</option> <option value="https://guides.rubyonrails.org/v3.2/">3.2</option> <option value="https://guides.rubyonrails.org/v3.1/">3.1</option> <option value="https://guides.rubyonrails.org/v3.0/">3.0</option> <option value="https://guides.rubyonrails.org/v2.3/">2.3</option> </select> </span> </div> <ul class="nav"> <li><a class="nav-item" id="home_nav" href="https://rubyonrails.org/">Home</a></li> <li class="guides-index guides-index-large"> <a href="index.html" id="guides-menu-button" data-aria-controls="guides" data-aria-expanded="false" class="guides-index-item nav-item">Guides Index</a> <div id="guides" class="clearfix" style="display: none;"> <hr /> <dl class="guides-section-container"> <div class="guides-section"> <dt>Start Here</dt> <dd><a href="getting_started.html">Getting Started with Rails</a></dd> </div> <div class="guides-section"> <dt>Models</dt> <dd><a href="active_record_basics.html">Active Record Basics</a></dd> <dd><a href="active_record_migrations.html">Active Record Migrations</a></dd> <dd><a href="active_record_validations.html">Active Record Validations</a></dd> <dd><a href="active_record_callbacks.html">Active Record Callbacks</a></dd> <dd><a href="association_basics.html">Active Record Associations</a></dd> <dd><a href="active_record_querying.html">Active Record Query Interface</a></dd> <dd><a href="active_model_basics.html">Active Model Basics</a></dd> </div> <div class="guides-section"> <dt>Views</dt> <dd><a href="action_view_overview.html">Action View Overview</a></dd> <dd><a href="layouts_and_rendering.html">Layouts and Rendering in Rails</a></dd> <dd><a href="action_view_helpers.html">Action View Helpers</a></dd> <dd><a href="form_helpers.html">Action View Form Helpers</a></dd> </div> <div class="guides-section"> <dt>Controllers</dt> <dd><a href="action_controller_overview.html">Action Controller Overview</a></dd> <dd><a href="routing.html">Rails Routing from the Outside In</a></dd> </div> <div class="guides-section"> <dt>Other Components</dt> <dd><a href="active_support_core_extensions.html">Active Support Core Extensions</a></dd> <dd><a href="action_mailer_basics.html">Action Mailer Basics</a></dd> <dd><a href="action_mailbox_basics.html">Action Mailbox Basics</a></dd> <dd><a href="action_text_overview.html">Action Text Overview</a></dd> <dd><a href="active_job_basics.html">Active Job Basics</a></dd> <dd><a href="active_storage_overview.html">Active Storage Overview</a></dd> <dd><a href="action_cable_overview.html">Action Cable Overview</a></dd> </div> <div class="guides-section"> <dt>Digging Deeper</dt> <dd><a href="i18n.html">Rails Internationalization (I18n) API</a></dd> <dd><a href="testing.html">Testing Rails Applications</a></dd> <dd><a href="security.html">Securing Rails Applications</a></dd> <dd><a href="error_reporting.html">Error Reporting in Rails Applications</a></dd> <dd><a href="debugging_rails_applications.html">Debugging Rails Applications</a></dd> <dd><a href="configuring.html">Configuring Rails Applications</a></dd> <dd><a href="command_line.html">The Rails Command Line</a></dd> <dd><a href="asset_pipeline.html">The Asset Pipeline</a></dd> <dd><a href="working_with_javascript_in_rails.html">Working with JavaScript in Rails</a></dd> <dd><a href="autoloading_and_reloading_constants.html">Autoloading and Reloading</a></dd> <dd><a href="caching_with_rails.html">Caching with Rails: An Overview</a></dd> <dd><a href="api_app.html">Using Rails for API-only Applications</a></dd> <dd><a href="tuning_performance_for_deployment.html">Tuning Performance for Deployment</a></dd> </div> <div class="guides-section"> <dt>Advanced Active Record</dt> <dd><a href="active_record_multiple_databases.html">Multiple Databases</a></dd> <dd><a href="active_record_composite_primary_keys.html">Composite Primary Keys</a></dd> </div> <div class="guides-section"> <dt>Extending Rails</dt> <dd><a href="rails_on_rack.html">Rails on Rack</a></dd> <dd><a href="generators.html">Creating and Customizing Rails Generators & Templates</a></dd> </div> <div class="guides-section"> <dt>Contributing</dt> <dd><a href="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</a></dd> <dd><a href="api_documentation_guidelines.html">API Documentation Guidelines</a></dd> <dd><a href="ruby_on_rails_guides_guidelines.html">Guides Guidelines</a></dd> <dd><a href="development_dependencies_install.html">Installing Rails Core Development Dependencies</a></dd> </div> <div class="guides-section"> <dt>Policies</dt> <dd><a href="maintenance_policy.html">Maintenance Policy</a></dd> </div> <div class="guides-section"> <dt>Release Notes</dt> <dd><a href="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</a></dd> <dd><a href="7_2_release_notes.html">Version 7.2 - August 2024</a></dd> <dd><a href="7_1_release_notes.html">Version 7.1 - October 2023</a></dd> <dd><a href="7_0_release_notes.html">Version 7.0 - December 2021</a></dd> <dd><a href="6_1_release_notes.html">Version 6.1 - December 2020</a></dd> <dd><a href="6_0_release_notes.html">Version 6.0 - August 2019</a></dd> <dd><a href="5_2_release_notes.html">Version 5.2 - April 2018</a></dd> <dd><a href="5_1_release_notes.html">Version 5.1 - April 2017</a></dd> <dd><a href="5_0_release_notes.html">Version 5.0 - June 2016</a></dd> <dd><a href="4_2_release_notes.html">Version 4.2 - December 2014</a></dd> <dd><a href="4_1_release_notes.html">Version 4.1 - April 2014</a></dd> <dd><a href="4_0_release_notes.html">Version 4.0 - June 2013</a></dd> <dd><a href="3_2_release_notes.html">Version 3.2 - January 2012</a></dd> <dd><a href="3_1_release_notes.html">Version 3.1 - August 2011</a></dd> <dd><a href="3_0_release_notes.html">Version 3.0 - August 2010</a></dd> <dd><a href="2_3_release_notes.html">Version 2.3 - March 2009</a></dd> <dd><a href="2_2_release_notes.html">Version 2.2 - November 2008</a></dd> </div> </dl> </div> </li> <li><a class="nav-item" href="contributing_to_ruby_on_rails.html">Contribute</a></li> <li class="guides-index guides-index-small js-only"> <label for="guides-selector"> Navigate to a guide: </label> <select id="guides-selector" class="guides-index-item nav-item"> <option value="index.html">Guides Index</option> <optgroup label="Start Here"> <option value="getting_started.html">Getting Started with Rails</option> </optgroup> <optgroup label="Models"> <option value="active_record_basics.html">Active Record Basics</option> <option value="active_record_migrations.html">Active Record Migrations</option> <option value="active_record_validations.html">Active Record Validations</option> <option value="active_record_callbacks.html">Active Record Callbacks</option> <option value="association_basics.html">Active Record Associations</option> <option value="active_record_querying.html">Active Record Query Interface</option> <option value="active_model_basics.html">Active Model Basics</option> </optgroup> <optgroup label="Views"> <option value="action_view_overview.html">Action View Overview</option> <option value="layouts_and_rendering.html">Layouts and Rendering in Rails</option> <option value="action_view_helpers.html">Action View Helpers</option> <option value="form_helpers.html">Action View Form Helpers</option> </optgroup> <optgroup label="Controllers"> <option value="action_controller_overview.html">Action Controller Overview</option> <option value="routing.html">Rails Routing from the Outside In</option> </optgroup> <optgroup label="Other Components"> <option value="active_support_core_extensions.html">Active Support Core Extensions</option> <option value="action_mailer_basics.html">Action Mailer Basics</option> <option value="action_mailbox_basics.html">Action Mailbox Basics</option> <option value="action_text_overview.html">Action Text Overview</option> <option value="active_job_basics.html">Active Job Basics</option> <option value="active_storage_overview.html">Active Storage Overview</option> <option value="action_cable_overview.html">Action Cable Overview</option> </optgroup> <optgroup label="Digging Deeper"> <option value="i18n.html">Rails Internationalization (I18n) API</option> <option value="testing.html">Testing Rails Applications</option> <option value="security.html">Securing Rails Applications</option> <option value="error_reporting.html">Error Reporting in Rails Applications</option> <option value="debugging_rails_applications.html">Debugging Rails Applications</option> <option value="configuring.html">Configuring Rails Applications</option> <option value="command_line.html">The Rails Command Line</option> <option value="asset_pipeline.html">The Asset Pipeline</option> <option value="working_with_javascript_in_rails.html">Working with JavaScript in Rails</option> <option value="autoloading_and_reloading_constants.html">Autoloading and Reloading</option> <option value="caching_with_rails.html">Caching with Rails: An Overview</option> <option value="api_app.html">Using Rails for API-only Applications</option> <option value="tuning_performance_for_deployment.html">Tuning Performance for Deployment</option> </optgroup> <optgroup label="Advanced Active Record"> <option value="active_record_multiple_databases.html">Multiple Databases</option> <option value="active_record_composite_primary_keys.html">Composite Primary Keys</option> </optgroup> <optgroup label="Extending Rails"> <option value="rails_on_rack.html">Rails on Rack</option> <option value="generators.html">Creating and Customizing Rails Generators & Templates</option> </optgroup> <optgroup label="Contributing"> <option value="contributing_to_ruby_on_rails.html">Contributing to Ruby on Rails</option> <option value="api_documentation_guidelines.html">API Documentation Guidelines</option> <option value="ruby_on_rails_guides_guidelines.html">Guides Guidelines</option> <option value="development_dependencies_install.html">Installing Rails Core Development Dependencies</option> </optgroup> <optgroup label="Policies"> <option value="maintenance_policy.html">Maintenance Policy</option> </optgroup> <optgroup label="Release Notes"> <option value="upgrading_ruby_on_rails.html">Upgrading Ruby on Rails</option> <option value="7_2_release_notes.html">Version 7.2 - August 2024</option> <option value="7_1_release_notes.html">Version 7.1 - October 2023</option> <option value="7_0_release_notes.html">Version 7.0 - December 2021</option> <option value="6_1_release_notes.html">Version 6.1 - December 2020</option> <option value="6_0_release_notes.html">Version 6.0 - August 2019</option> <option value="5_2_release_notes.html">Version 5.2 - April 2018</option> <option value="5_1_release_notes.html">Version 5.1 - April 2017</option> <option value="5_0_release_notes.html">Version 5.0 - June 2016</option> <option value="4_2_release_notes.html">Version 4.2 - December 2014</option> <option value="4_1_release_notes.html">Version 4.1 - April 2014</option> <option value="4_0_release_notes.html">Version 4.0 - June 2013</option> <option value="3_2_release_notes.html">Version 3.2 - January 2012</option> <option value="3_1_release_notes.html">Version 3.1 - August 2011</option> <option value="3_0_release_notes.html">Version 3.0 - August 2010</option> <option value="2_3_release_notes.html">Version 2.3 - March 2009</option> <option value="2_2_release_notes.html">Version 2.2 - November 2008</option> </optgroup> </select> </li> </ul> </nav> </div> </header> <hr class="hide" /> <main id="main"> <article> <header id="feature"> <div class="wrapper"> <h1>Rails Routing from the Outside In</h1><p>This guide covers the user-facing features of Rails routing.</p><p>After reading this guide, you will know:</p> <ul> <li>How to interpret the code in <code>config/routes.rb</code>.</li> <li>How to construct your own routes, using either the preferred resourceful style or the <code>match</code> method.</li> <li>How to declare route parameters, which are passed onto controller actions.</li> <li>How to automatically create paths and URLs using route helpers.</li> <li>Advanced techniques such as creating constraints and mounting Rack endpoints.</li> </ul> <nav id="column-side" aria-label="Chapter" class="guide-index" data-turbo="false"> <a id="chapter-nav-skip-link" href="#article-body" class="skip-link"> Skip to article body </a> <h2 class="chapter"> <picture aria-hidden="true"> <!-- Using the `source` HTML tag to set the dark theme image --> <source srcset="images/icon_book-close-bookmark-1-wht.svg" media="(prefers-color-scheme: dark)" /> <img src="images/icon_book-close-bookmark-1.svg" alt="Chapter Icon" /> </picture> Chapters </h2> <ol class="chapters"> <li><a href="#the-purpose-of-the-rails-router">The Purpose of the Rails Router</a> <ul> <li><a href="#routing-incoming-urls-to-code">Routing Incoming URLs to Code</a></li> <li><a href="#generating-paths-and-urls-from-code">Generating Paths and URLs from Code</a></li> <li><a href="#configuring-the-rails-router">Configuring the Rails Router</a></li> </ul></li> <li><a href="#resource-routing-the-rails-default">Resource Routing: the Rails Default</a> <ul> <li><a href="#resources-on-the-web">Resources on the Web</a></li> <li><a href="#crud-verbs-and-actions">CRUD, Verbs, and Actions</a></li> <li><a href="#path-and-url-helpers">Path and URL Helpers</a></li> <li><a href="#defining-multiple-resources-at-the-same-time">Defining Multiple Resources at the Same Time</a></li> <li><a href="#singular-resources">Singular Resources</a></li> <li><a href="#controller-namespaces-and-routing">Controller Namespaces and Routing</a></li> <li><a href="#nested-resources">Nested Resources</a></li> <li><a href="#routing-concerns">Routing Concerns</a></li> <li><a href="#creating-paths-and-urls-from-objects">Creating Paths and URLs from Objects</a></li> <li><a href="#adding-more-restful-routes">Adding More RESTful Routes</a></li> </ul></li> <li><a href="#non-resourceful-routes">Non-Resourceful Routes</a> <ul> <li><a href="#bound-parameters">Bound Parameters</a></li> <li><a href="#dynamic-segments">Dynamic Segments</a></li> <li><a href="#static-segments">Static Segments</a></li> <li><a href="#the-query-string">The Query String</a></li> <li><a href="#defining-default-parameters">Defining Default Parameters</a></li> <li><a href="#naming-routes">Naming Routes</a></li> <li><a href="#http-verb-constraints">HTTP Verb Constraints</a></li> <li><a href="#segment-constraints">Segment Constraints</a></li> <li><a href="#request-based-constraints">Request-Based Constraints</a></li> <li><a href="#advanced-constraints">Advanced Constraints</a></li> <li><a href="#wildcard-segments">Wildcard Segments</a></li> <li><a href="#format-segments">Format Segments</a></li> <li><a href="#redirection">Redirection</a></li> <li><a href="#routing-to-rack-applications">Routing to Rack Applications</a></li> <li><a href="#using-root">Using <code>root</code></a></li> <li><a href="#unicode-character-routes">Unicode Character Routes</a></li> <li><a href="#direct-routes">Direct Routes</a></li> <li><a href="#using-resolve">Using <code>resolve</code></a></li> </ul></li> <li><a href="#customizing-resourceful-routes">Customizing Resourceful Routes</a> <ul> <li><a href="#specifying-a-controller-to-use">Specifying a Controller to Use</a></li> <li><a href="#specifying-constraints-on-id">Specifying Constraints on <code>id</code></a></li> <li><a href="#overriding-the-named-route-helpers">Overriding the Named Route Helpers</a></li> <li><a href="#renaming-the-new-and-edit-path-names">Renaming the <code>new</code> and <code>edit</code> Path Names</a></li> <li><a href="#prefixing-the-named-route-helpers-with-as">Prefixing the Named Route Helpers with <code>:as</code></a></li> <li><a href="#using-as-in-nested-resources">Using <code>:as</code> in Nested Resources</a></li> <li><a href="#parametric-scopes">Parametric Scopes</a></li> <li><a href="#restricting-the-routes-created">Restricting the Routes Created</a></li> <li><a href="#translated-paths">Translated Paths</a></li> <li><a href="#specifying-the-singular-form-of-a-resource">Specifying the Singular Form of a Resource</a></li> <li><a href="#renaming-default-route-parameter-id">Renaming Default Route Parameter <code>id</code></a></li> </ul></li> <li><a href="#inspecting-routes">Inspecting Routes</a> <ul> <li><a href="#listing-existing-routes">Listing Existing Routes</a></li> <li><a href="#searching-routes">Searching Routes</a></li> <li><a href="#listing-unused-routes">Listing Unused Routes</a></li> <li><a href="#routes-in-rails-console">Routes in Rails Console</a></li> </ul></li> <li><a href="#testing-routes">Testing Routes</a> <ul> <li><a href="#the-assert-generates-assertion">The <code>assert_generates</code> Assertion</a></li> <li><a href="#the-assert-recognizes-assertion">The <code>assert_recognizes</code> Assertion</a></li> <li><a href="#the-assert-routing-assertion">The <code>assert_routing</code> Assertion</a></li> </ul></li> <li><a href="#breaking-up-a-large-route-file-with-draw">Breaking Up a Large Route File With <code>draw</code></a></li> </ol> </nav> </div> </header> <div class="wrapper"> <div id="column-main"> <section id="article-body"> <h2 id="the-purpose-of-the-rails-router"><a class="anchorlink" href="#the-purpose-of-the-rails-router" data-turbo="false"><span>1</span> The Purpose of the Rails Router</a></h2><p>The Rails router matches incoming HTTP requests to specific controller actions in your Rails application based on the URL path. (It can also forward to a <a href="rails_on_rack.html">Rack</a> application.) The router also generates path and URL helpers based on the resources configured in the router.</p><h3 id="routing-incoming-urls-to-code"><a class="anchorlink" href="#routing-incoming-urls-to-code" data-turbo="false"><span>1.1</span> Routing Incoming URLs to Code</a></h3><p>When your Rails application receives an incoming request, it asks the router to match it to a controller action (aka method). For example, take the following incoming request:</p><div class="interstitial code"> <pre><code class="highlight plaintext">GET /users/17 </code></pre> <button class="clipboard-button" data-clipboard-text="GET /users/17 ">Copy</button> </div> <p>If the first matching route is:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/users/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"user#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/users/:id", to: "user#show" ">Copy</button> </div> <p>The request is matched to the <code>UsersController</code> class's <code>show</code> action with <code>{ id: '17' }</code> in the <code>params</code> hash.</p><p>The <code>to:</code> option expects a <code>controller#action</code> format when passed a string. Alternatively, You can pass a symbol and use the <code>action:</code> option, instead of <code>to:</code>. You can also pass a string without a <code>#</code>, in which case the <code>controller:</code> option is used instead to <code>to:</code>. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/users/:id"</span><span class="p">,</span> <span class="ss">controller: </span><span class="s2">"users"</span><span class="p">,</span> <span class="ss">action: :show</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/users/:id", controller: "users", action: :show ">Copy</button> </div> <div class="interstitial note"><p>Rails uses snake_case for controller names when specifying routes. For example, if you have a controller named <code>UserProfilesController</code>, you would specify a route to the show action as <code>user_profiles#show</code>.</p></div><h3 id="generating-paths-and-urls-from-code"><a class="anchorlink" href="#generating-paths-and-urls-from-code" data-turbo="false"><span>1.2</span> Generating Paths and URLs from Code</a></h3><p>The Router automatically generates path and URL helper methods for your application. With these methods you can avoid hard-coded path and URL strings.</p><p>For example, the <code>user_path</code> and <code>user_url</code> helper methods are available when defining the following route:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/users/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"users#show"</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"user"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/users/:id", to: "users#show", as: "user" ">Copy</button> </div> <div class="interstitial note"><p>The <code>as:</code> option is used to provide a custom name for a route, which is used when generating URL and path helpers.</p></div><p>Assuming your application contains this code in the controller:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="vi">@user</span> <span class="o">=</span> <span class="no">User</span><span class="p">.</span><span class="nf">find</span><span class="p">(</span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span> </code></pre> <button class="clipboard-button" data-clipboard-text="@user = User.find(params[:id]) ">Copy</button> </div> <p>and this in the corresponding view:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'User Record'</span><span class="p">,</span> <span class="n">user_path</span><span class="p">(</span><span class="vi">@user</span><span class="p">)</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'User Record', user_path(@user) %> ">Copy</button> </div> <p>The router will generate the path <code>/users/17</code> from <code>user_path(@user)</code>. Using the <code>user_path</code> helper allows you to avoid having to hard-code a path in your views. This is helpful if you eventually move the route to a different URL, as you won't need to update the corresponding views.</p><p>It also generates <code>user_url</code>, which has a similar purpose. While <code>user_path</code> generates a relative URL like <code>/users/17</code>, <code>user_url</code> generates an absolute URL such as <code>https://example.com/users/17</code> in the above example.</p><h3 id="configuring-the-rails-router"><a class="anchorlink" href="#configuring-the-rails-router" data-turbo="false"><span>1.3</span> Configuring the Rails Router</a></h3><p>Routes live in <code>config/routes.rb</code>. Here is an example of what routes look like in a typical Rails application. The sections that follow will explain the different route helpers used in this file:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:brands</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:show</span><span class="p">]</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:products</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:show</span><span class="p">]</span> <span class="k">end</span> <span class="n">resource</span> <span class="ss">:basket</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">,</span> <span class="ss">:update</span><span class="p">,</span> <span class="ss">:destroy</span><span class="p">]</span> <span class="n">resolve</span><span class="p">(</span><span class="s2">"Basket"</span><span class="p">)</span> <span class="p">{</span> <span class="n">route_for</span><span class="p">(</span><span class="ss">:basket</span><span class="p">)</span> <span class="p">}</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="Rails.application.routes.draw do resources :brands, only: [:index, :show] do resources :products, only: [:index, :show] end resource :basket, only: [:show, :update, :destroy] resolve("Basket") { route_for(:basket) } end ">Copy</button> </div> <p>Since this is a regular Ruby source file, you can use all of Ruby's features (like conditionals and loops) to help you define your routes.</p><div class="interstitial note"><p>The <code>Rails.application.routes.draw do ... end</code> block that wraps your route definitions is required to establish the scope for the router DSL (Domain Specific Language) and must not be deleted.</p></div><div class="interstitial warning"><p>Be careful with variable names in <code>routes.rb</code> as they can clash with the DSL methods of the router.</p></div><h2 id="resource-routing-the-rails-default"><a class="anchorlink" href="#resource-routing-the-rails-default" data-turbo="false"><span>2</span> Resource Routing: the Rails Default</a></h2><p>Resource routing allows you to quickly declare all of the common routes for a given resource controller. For example, a single call to <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources"><code>resources</code></a> declares all of the necessary routes for the <code>index</code>, <code>show</code>, <code>new</code>, <code>edit</code>, <code>create</code>, <code>update</code>, and <code>destroy</code> actions, without you having to declare each route separately.</p><h3 id="resources-on-the-web"><a class="anchorlink" href="#resources-on-the-web" data-turbo="false"><span>2.1</span> Resources on the Web</a></h3><p>Browsers request pages from Rails by making a request for a URL using a specific HTTP verb, such as <code>GET</code>, <code>POST</code>, <code>PATCH</code>, <code>PUT</code>, and <code>DELETE</code>. Each HTTP verb is a request to perform an operation on the resource. A resource route maps related requests to actions in a single controller.</p><p>When your Rails application receives an incoming request for:</p><div class="interstitial code"> <pre><code class="highlight plaintext">DELETE /photos/17 </code></pre> <button class="clipboard-button" data-clipboard-text="DELETE /photos/17 ">Copy</button> </div> <p>it asks the router to map it to a controller action. If the first matching route is:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos ">Copy</button> </div> <p>Rails would dispatch that request to the <code>destroy</code> action on the <code>PhotosController</code> with <code>{ id: '17' }</code> in <code>params</code>.</p><h3 id="crud-verbs-and-actions"><a class="anchorlink" href="#crud-verbs-and-actions" data-turbo="false"><span>2.2</span> CRUD, Verbs, and Actions</a></h3><p>In Rails, resourceful routes provide a mapping from incoming requests (a combination of HTTP verb + URL) to controller actions. By convention, each action generally maps to a specific <a href="active_record_basics.html#crud-reading-and-writing-data">CRUD</a> operation on your data. A single entry in the routing file, such as:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos ">Copy</button> </div> <p>creates seven different routes in your application, all mapping to the <code>PhotosController</code> actions:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Used to</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/photos</td> <td>photos#index</td> <td>display a list of all photos</td> </tr> <tr> <td>GET</td> <td>/photos/new</td> <td>photos#new</td> <td>return an HTML form for creating a new photo</td> </tr> <tr> <td>POST</td> <td>/photos</td> <td>photos#create</td> <td>create a new photo</td> </tr> <tr> <td>GET</td> <td>/photos/:id</td> <td>photos#show</td> <td>display a specific photo</td> </tr> <tr> <td>GET</td> <td>/photos/:id/edit</td> <td>photos#edit</td> <td>return an HTML form for editing a photo</td> </tr> <tr> <td>PATCH/PUT</td> <td>/photos/:id</td> <td>photos#update</td> <td>update a specific photo</td> </tr> <tr> <td>DELETE</td> <td>/photos/:id</td> <td>photos#destroy</td> <td>delete a specific photo</td> </tr> </tbody></table></div> <p>Since the router uses the HTTP verb <em>and</em> path to match inbound requests, four URLs can map to seven different controller actions. For example, the same <code>photos/</code> path matches to <code>photos#index</code> when the verb is <code>GET</code> and <code>photos#create</code> when the verb is <code>POST</code>.</p><div class="interstitial note"><p>Order matters in the <code>routes.rb</code> file. Rails routes are matched in the order they are specified. For example, if you have a <code>resources :photos</code> above a <code>get 'photos/poll'</code> the <code>show</code> action's route for the <code>resources</code> line will be matched before the <code>get</code> line. If you want the <code>photos/poll</code> route to match first, you'll need to move the <code>get</code> line <strong>above</strong> the <code>resources</code> line.</p></div><h3 id="path-and-url-helpers"><a class="anchorlink" href="#path-and-url-helpers" data-turbo="false"><span>2.3</span> Path and URL Helpers</a></h3><p>Creating a resourceful route will also expose a number of helpers to controllers and views in your application.</p><p>For example, adding <code>resources :photos</code> to the route file will generate these <code>_path</code> helpers:</p> <div class="table-wrapper"><table><thead> <tr> <th>Path Helper</th> <th>Returns URL</th> </tr> </thead><tbody> <tr> <td><code>photos_path</code></td> <td>/photos</td> </tr> <tr> <td><code>new_photo_path</code></td> <td>/photos/new</td> </tr> <tr> <td><code>edit_photo_path(:id)</code></td> <td>/photos/:id/edit`</td> </tr> <tr> <td><code>photo_path(:id)</code></td> <td>/photos/:id</td> </tr> </tbody></table></div> <p>Parameters to the path helpers, such as <code>:id</code> above, are passed to the generated URL, such that <code>edit_photo_path(10)</code> will return <code>/photos/10/edit</code>.</p><p>Each of these <code>_path</code> helpers also have a corresponding <code>_url</code> helper (such as <code>photos_url</code>) which returns the same path prefixed with the current host, port, and path prefix.</p><div class="interstitial info"><p>The prefix used before "_path" and "_url" is the route name and can be identified by looking at the "prefix" column of the <code>rails routes</code> command output. To learn more see <a href="#listing-existing-routes">Listing Existing Routes</a> below.</p></div><h3 id="defining-multiple-resources-at-the-same-time"><a class="anchorlink" href="#defining-multiple-resources-at-the-same-time" data-turbo="false"><span>2.4</span> Defining Multiple Resources at the Same Time</a></h3><p>If you need to create routes for more than one resource, you can save a bit of typing by defining them all with a single call to <code>resources</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">:books</span><span class="p">,</span> <span class="ss">:videos</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, :books, :videos ">Copy</button> </div> <p>The above is a shortcut for:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> <span class="n">resources</span> <span class="ss">:books</span> <span class="n">resources</span> <span class="ss">:videos</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos resources :books resources :videos ">Copy</button> </div> <h3 id="singular-resources"><a class="anchorlink" href="#singular-resources" data-turbo="false"><span>2.5</span> Singular Resources</a></h3><p>Sometimes, you have a resource that users expect to have only one (i.e. it does not make sense to have an <code>index</code> action to list all values of that resource). In that case, you can use <code>resource</code> (singular) instead of <code>resources</code>.</p><p>The below resourceful route creates six routes in your application, all mapping to the <code>Geocoders</code> controller:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resource</span> <span class="ss">:geocoder</span> <span class="n">resolve</span><span class="p">(</span><span class="s2">"Geocoder"</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="ss">:geocoder</span><span class="p">]</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resource :geocoder resolve("Geocoder") { [:geocoder] } ">Copy</button> </div> <div class="interstitial note"><p>The call to <code>resolve</code> is necessary for converting instances of the <code>Geocoder</code> to singular routes through <a href="form_helpers.html#relying-on-record-identification">record identification</a>.</p></div><p>Here are all of the routes created for a singular resource:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Used to</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/geocoder/new</td> <td>geocoders#new</td> <td>return an HTML form for creating the geocoder</td> </tr> <tr> <td>POST</td> <td>/geocoder</td> <td>geocoders#create</td> <td>create the new geocoder</td> </tr> <tr> <td>GET</td> <td>/geocoder</td> <td>geocoders#show</td> <td>display the one and only geocoder resource</td> </tr> <tr> <td>GET</td> <td>/geocoder/edit</td> <td>geocoders#edit</td> <td>return an HTML form for editing the geocoder</td> </tr> <tr> <td>PATCH/PUT</td> <td>/geocoder</td> <td>geocoders#update</td> <td>update the one and only geocoder resource</td> </tr> <tr> <td>DELETE</td> <td>/geocoder</td> <td>geocoders#destroy</td> <td>delete the geocoder resource</td> </tr> </tbody></table></div> <div class="interstitial note"><p>Singular resources map to plural controllers. For example, the <code>geocoder</code> resource maps to the <code>GeocodersController</code>.</p></div><p>A singular resourceful route generates these helpers:</p> <ul> <li><code>new_geocoder_path</code> returns <code>/geocoder/new</code></li> <li><code>edit_geocoder_path</code> returns <code>/geocoder/edit</code></li> <li><code>geocoder_path</code> returns <code>/geocoder</code></li> </ul> <p>As with plural resources, the same helpers ending in <code>_url</code> will also include the host, port, and path prefix.</p><h3 id="controller-namespaces-and-routing"><a class="anchorlink" href="#controller-namespaces-and-routing" data-turbo="false"><span>2.6</span> Controller Namespaces and Routing</a></h3><p>In large applications, you may wish to organize groups of controllers under a namespace. For example, you may have a number of controllers under an <code>Admin::</code> namespace, which are inside the <code>app/controllers/admin</code> directory. You can route to such a group by using a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-namespace"><code>namespace</code></a> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">namespace</span> <span class="ss">:admin</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="namespace :admin do resources :articles end ">Copy</button> </div> <p>This will create a number of routes for each of the <code>articles</code> and <code>comments</code> controller. For <code>Admin::ArticlesController</code>, Rails will create:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/admin/articles</td> <td>admin/articles#index</td> <td>admin_articles_path</td> </tr> <tr> <td>GET</td> <td>/admin/articles/new</td> <td>admin/articles#new</td> <td>new_admin_article_path</td> </tr> <tr> <td>POST</td> <td>/admin/articles</td> <td>admin/articles#create</td> <td>admin_articles_path</td> </tr> <tr> <td>GET</td> <td>/admin/articles/:id</td> <td>admin/articles#show</td> <td>admin_article_path(:id)</td> </tr> <tr> <td>GET</td> <td>/admin/articles/:id/edit</td> <td>admin/articles#edit</td> <td>edit_admin_article_path(:id)</td> </tr> <tr> <td>PATCH/PUT</td> <td>/admin/articles/:id</td> <td>admin/articles#update</td> <td>admin_article_path(:id)</td> </tr> <tr> <td>DELETE</td> <td>/admin/articles/:id</td> <td>admin/articles#destroy</td> <td>admin_article_path(:id)</td> </tr> </tbody></table></div> <p>Note that in the above example all of the paths have a <code>/admin</code> prefix per the default convention for <code>namespace</code>.</p><h4 id="using-module"><a class="anchorlink" href="#using-module" data-turbo="false"><span>2.6.1</span> Using Module</a></h4><p>If you want to route <code>/articles</code> (without the prefix <code>/admin</code>) to <code>Admin::ArticlesController</code>, you can specify the module with a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-scope"><code>scope</code></a> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="ss">module: </span><span class="s2">"admin"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope module: "admin" do resources :articles end ">Copy</button> </div> <p>Another way to write the above:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">module: </span><span class="s2">"admin"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :articles, module: "admin" ">Copy</button> </div> <h4 id="using-scope"><a class="anchorlink" href="#using-scope" data-turbo="false"><span>2.6.2</span> Using Scope</a></h4><p>Alternatively, you can also route <code>/admin/articles</code> to <code>ArticlesController</code> (without the <code>Admin::</code> module prefix). You can specify the path with a <code>scope</code> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="s2">"/admin"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope "/admin" do resources :articles end ">Copy</button> </div> <p>Another way to write the above:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">path: </span><span class="s2">"/admin/articles"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :articles, path: "/admin/articles" ">Copy</button> </div> <p>For these alternatives (without <code>/admin</code> in path and without <code>Admin::</code> in module prefix), the named route helpers remain the same as if you did not use <code>scope</code>.</p><p>In the last case, the following paths map to <code>ArticlesController</code>:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/admin/articles</td> <td>articles#index</td> <td>articles_path</td> </tr> <tr> <td>GET</td> <td>/admin/articles/new</td> <td>articles#new</td> <td>new_article_path</td> </tr> <tr> <td>POST</td> <td>/admin/articles</td> <td>articles#create</td> <td>articles_path</td> </tr> <tr> <td>GET</td> <td>/admin/articles/:id</td> <td>articles#show</td> <td>article_path(:id)</td> </tr> <tr> <td>GET</td> <td>/admin/articles/:id/edit</td> <td>articles#edit</td> <td>edit_article_path(:id)</td> </tr> <tr> <td>PATCH/PUT</td> <td>/admin/articles/:id</td> <td>articles#update</td> <td>article_path(:id)</td> </tr> <tr> <td>DELETE</td> <td>/admin/articles/:id</td> <td>articles#destroy</td> <td>article_path(:id)</td> </tr> </tbody></table></div> <div class="interstitial info"><p>If you need to use a different controller namespace inside a <code>namespace</code> block you can specify an absolute controller path, e.g: <code>get '/foo', to: '/foo#index'</code>.</p></div><h3 id="nested-resources"><a class="anchorlink" href="#nested-resources" data-turbo="false"><span>2.7</span> Nested Resources</a></h3><p>It's common to have resources that are logically children of other resources. For example, suppose your application includes these models:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">Magazine</span> <span class="o"><</span> <span class="no">ApplicationRecord</span> <span class="n">has_many</span> <span class="ss">:ads</span> <span class="k">end</span> <span class="k">class</span> <span class="nc">Ad</span> <span class="o"><</span> <span class="no">ApplicationRecord</span> <span class="n">belongs_to</span> <span class="ss">:magazine</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class Magazine < ApplicationRecord has_many :ads end class Ad < ApplicationRecord belongs_to :magazine end ">Copy</button> </div> <p>Nested route declarations allow you to capture this relationship in your routing:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:magazines</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:ads</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :magazines do resources :ads end ">Copy</button> </div> <p>In addition to the routes for magazines, this declaration will also route ads to an <code>AdsController</code>. Here are all of the routes for the nested <code>ads</code> resource:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Used to</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/magazines/:magazine_id/ads</td> <td>ads#index</td> <td>display a list of all ads for a specific magazine</td> </tr> <tr> <td>GET</td> <td>/magazines/:magazine_id/ads/new</td> <td>ads#new</td> <td>return an HTML form for creating a new ad belonging to a specific magazine</td> </tr> <tr> <td>POST</td> <td>/magazines/:magazine_id/ads</td> <td>ads#create</td> <td>create a new ad belonging to a specific magazine</td> </tr> <tr> <td>GET</td> <td>/magazines/:magazine_id/ads/:id</td> <td>ads#show</td> <td>display a specific ad belonging to a specific magazine</td> </tr> <tr> <td>GET</td> <td>/magazines/:magazine_id/ads/:id/edit</td> <td>ads#edit</td> <td>return an HTML form for editing an ad belonging to a specific magazine</td> </tr> <tr> <td>PATCH/PUT</td> <td>/magazines/:magazine_id/ads/:id</td> <td>ads#update</td> <td>update a specific ad belonging to a specific magazine</td> </tr> <tr> <td>DELETE</td> <td>/magazines/:magazine_id/ads/:id</td> <td>ads#destroy</td> <td>delete a specific ad belonging to a specific magazine</td> </tr> </tbody></table></div> <p>This will also create the usual path and url routing helpers such as <code>magazine_ads_url</code> and <code>edit_magazine_ad_path</code>. Since the <code>ads</code> resource is nested below <code>magazines</code>, The ad URLs require a magazine. The helpers can take an instance of <code>Magazine</code> as the first parameter (<code>edit_magazine_ad_path(@magazine, @ad)</code>).</p><h4 id="limits-to-nesting"><a class="anchorlink" href="#limits-to-nesting" data-turbo="false"><span>2.7.1</span> Limits to Nesting</a></h4><p>You can nest resources within other nested resources if you like. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:publishers</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:magazines</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :publishers do resources :magazines do resources :photos end end ">Copy</button> </div> <p>In the above example, the application would recognize paths such as:</p><div class="interstitial code"> <pre><code class="highlight plaintext">/publishers/1/magazines/2/photos/3 </code></pre> <button class="clipboard-button" data-clipboard-text="/publishers/1/magazines/2/photos/3 ">Copy</button> </div> <p>The corresponding route helper would be <code>publisher_magazine_photo_url</code>, requiring you to specify objects at all three levels. As you can see, deeply nested resources can become overly complex and cumbersome to maintain.</p><div class="interstitial info"><p>The general rule of thumb is to only nest resources 1 level deep.</p></div><h4 id="shallow-nesting"><a class="anchorlink" href="#shallow-nesting" data-turbo="false"><span>2.7.2</span> Shallow Nesting</a></h4><p>One way to avoid deep nesting (as recommended above) is to generate the collection actions scoped under the parent - so as to get a sense of the hierarchy, but to not nest the member actions. In other words, to only build routes with the minimal amount of information to uniquely identify the resource.</p><div class="interstitial note"><p>The "member" actions are the ones that apply to an individual resource and require an ID to identify the specific resource they are acting upon, such as <code>show</code>, <code>edit</code>, etc. The "collection" actions are the ones that act on the entire set of the resource, such as <code>index</code>.</p></div><p>For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:new</span><span class="p">,</span> <span class="ss">:create</span><span class="p">]</span> <span class="k">end</span> <span class="n">resources</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:show</span><span class="p">,</span> <span class="ss">:edit</span><span class="p">,</span> <span class="ss">:update</span><span class="p">,</span> <span class="ss">:destroy</span><span class="p">]</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :articles do resources :comments, only: [:index, :new, :create] end resources :comments, only: [:show, :edit, :update, :destroy] ">Copy</button> </div> <p>Above we use the <code>:only</code> option which tells Rails to create only the specified routes. This idea strikes a balance between descriptive routes and deep nesting. There is a shorthand syntax to achieve just that, via the <code>:shallow</code> option:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">shallow: </span><span class="kp">true</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :articles do resources :comments, shallow: true end ">Copy</button> </div> <p>This will generate the exact same routes as the first example. You can also specify the <code>:shallow</code> option in the parent resource, in which case all of the nested resources will be shallow:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">shallow: </span><span class="kp">true</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="n">resources</span> <span class="ss">:quotes</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :articles, shallow: true do resources :comments resources :quotes end ">Copy</button> </div> <p>The articles resource above will generate the following routes:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#index</td> <td>article_comments_path</td> </tr> <tr> <td>POST</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#create</td> <td>article_comments_path</td> </tr> <tr> <td>GET</td> <td>/articles/:article_id/comments/new(.:format)</td> <td>comments#new</td> <td>new_article_comment_path</td> </tr> <tr> <td>GET</td> <td>/comments/:id/edit(.:format)</td> <td>comments#edit</td> <td>edit_comment_path</td> </tr> <tr> <td>GET</td> <td>/comments/:id(.:format)</td> <td>comments#show</td> <td>comment_path</td> </tr> <tr> <td>PATCH/PUT</td> <td>/comments/:id(.:format)</td> <td>comments#update</td> <td>comment_path</td> </tr> <tr> <td>DELETE</td> <td>/comments/:id(.:format)</td> <td>comments#destroy</td> <td>comment_path</td> </tr> <tr> <td>GET</td> <td>/articles/:article_id/quotes(.:format)</td> <td>quotes#index</td> <td>article_quotes_path</td> </tr> <tr> <td>POST</td> <td>/articles/:article_id/quotes(.:format)</td> <td>quotes#create</td> <td>article_quotes_path</td> </tr> <tr> <td>GET</td> <td>/articles/:article_id/quotes/new(.:format)</td> <td>quotes#new</td> <td>new_article_quote_path</td> </tr> <tr> <td>GET</td> <td>/quotes/:id/edit(.:format)</td> <td>quotes#edit</td> <td>edit_quote_path</td> </tr> <tr> <td>GET</td> <td>/quotes/:id(.:format)</td> <td>quotes#show</td> <td>quote_path</td> </tr> <tr> <td>PATCH/PUT</td> <td>/quotes/:id(.:format)</td> <td>quotes#update</td> <td>quote_path</td> </tr> <tr> <td>DELETE</td> <td>/quotes/:id(.:format)</td> <td>quotes#destroy</td> <td>quote_path</td> </tr> <tr> <td>GET</td> <td>/articles(.:format)</td> <td>articles#index</td> <td>articles_path</td> </tr> <tr> <td>POST</td> <td>/articles(.:format)</td> <td>articles#create</td> <td>articles_path</td> </tr> <tr> <td>GET</td> <td>/articles/new(.:format)</td> <td>articles#new</td> <td>new_article_path</td> </tr> <tr> <td>GET</td> <td>/articles/:id/edit(.:format)</td> <td>articles#edit</td> <td>edit_article_path</td> </tr> <tr> <td>GET</td> <td>/articles/:id(.:format)</td> <td>articles#show</td> <td>article_path</td> </tr> <tr> <td>PATCH/PUT</td> <td>/articles/:id(.:format)</td> <td>articles#update</td> <td>article_path</td> </tr> <tr> <td>DELETE</td> <td>/articles/:id(.:format)</td> <td>articles#destroy</td> <td>article_path</td> </tr> </tbody></table></div> <p>The <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-shallow"><code>shallow</code></a> method with a block creates a scope inside of which every nesting is shallow. This generates the same routes as the previous example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">shallow</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="n">resources</span> <span class="ss">:quotes</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="shallow do resources :articles do resources :comments resources :quotes end end ">Copy</button> </div> <p>There are two options that can be used with <code>scope</code> to customize shallow routes - <code>:shallow_path</code> and <code>:shallow_prefix</code>.</p><p>The <code>shallow_path</code> option prefixes member paths with the given parameter:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="ss">shallow_path: </span><span class="s2">"sekret"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">shallow: </span><span class="kp">true</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope shallow_path: "sekret" do resources :articles do resources :comments, shallow: true end end ">Copy</button> </div> <p>The comments resource here will have the following routes generated for it:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#index</td> <td>article_comments_path</td> </tr> <tr> <td>POST</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#create</td> <td>article_comments_path</td> </tr> <tr> <td>GET</td> <td>/articles/:article_id/comments/new(.:format)</td> <td>comments#new</td> <td>new_article_comment_path</td> </tr> <tr> <td>GET</td> <td>/sekret/comments/:id/edit(.:format)</td> <td>comments#edit</td> <td>edit_comment_path</td> </tr> <tr> <td>GET</td> <td>/sekret/comments/:id(.:format)</td> <td>comments#show</td> <td>comment_path</td> </tr> <tr> <td>PATCH/PUT</td> <td>/sekret/comments/:id(.:format)</td> <td>comments#update</td> <td>comment_path</td> </tr> <tr> <td>DELETE</td> <td>/sekret/comments/:id(.:format)</td> <td>comments#destroy</td> <td>comment_path</td> </tr> </tbody></table></div> <p>The <code>:shallow_prefix</code> option adds the specified parameter to the <code>_path</code> and <code>_url</code> route helpers:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="ss">shallow_prefix: </span><span class="s2">"sekret"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span><span class="p">,</span> <span class="ss">shallow: </span><span class="kp">true</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope shallow_prefix: "sekret" do resources :articles do resources :comments, shallow: true end end ">Copy</button> </div> <p>The comments resource here will have the following routes generated for it:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#index</td> <td>article_comments_path</td> </tr> <tr> <td>POST</td> <td>/articles/:article_id/comments(.:format)</td> <td>comments#create</td> <td>article_comments_path</td> </tr> <tr> <td>GET</td> <td>/articles/:article_id/comments/new(.:format)</td> <td>comments#new</td> <td>new_article_comment_path</td> </tr> <tr> <td>GET</td> <td>/comments/:id/edit(.:format)</td> <td>comments#edit</td> <td>edit_sekret_comment_path</td> </tr> <tr> <td>GET</td> <td>/comments/:id(.:format)</td> <td>comments#show</td> <td>sekret_comment_path</td> </tr> <tr> <td>PATCH/PUT</td> <td>/comments/:id(.:format)</td> <td>comments#update</td> <td>sekret_comment_path</td> </tr> <tr> <td>DELETE</td> <td>/comments/:id(.:format)</td> <td>comments#destroy</td> <td>sekret_comment_path</td> </tr> </tbody></table></div> <h3 id="routing-concerns"><a class="anchorlink" href="#routing-concerns" data-turbo="false"><span>2.8</span> Routing Concerns</a></h3><p>Routing concerns allow you to declare common routes that can be reused inside other resources. To define a concern, use a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Concerns.html#method-i-concern"><code>concern</code></a> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">concern</span> <span class="ss">:commentable</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="k">end</span> <span class="n">concern</span> <span class="ss">:image_attachable</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:images</span><span class="p">,</span> <span class="ss">only: :index</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="concern :commentable do resources :comments end concern :image_attachable do resources :images, only: :index end ">Copy</button> </div> <p>These concerns can be used in resources to avoid code duplication and share behavior across routes:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:messages</span><span class="p">,</span> <span class="ss">concerns: :commentable</span> <span class="n">resources</span> <span class="ss">:articles</span><span class="p">,</span> <span class="ss">concerns: </span><span class="p">[</span><span class="ss">:commentable</span><span class="p">,</span> <span class="ss">:image_attachable</span><span class="p">]</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :messages, concerns: :commentable resources :articles, concerns: [:commentable, :image_attachable] ">Copy</button> </div> <p>The above is equivalent to:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:messages</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="k">end</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="n">resources</span> <span class="ss">:images</span><span class="p">,</span> <span class="ss">only: :index</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :messages do resources :comments end resources :articles do resources :comments resources :images, only: :index end ">Copy</button> </div> <p>You can also call <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Concerns.html#method-i-concerns"><code>concerns</code></a> in a <code>scope</code> or <code>namespace</code> block to get the same result as above. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">namespace</span> <span class="ss">:messages</span> <span class="k">do</span> <span class="n">concerns</span> <span class="ss">:commentable</span> <span class="k">end</span> <span class="n">namespace</span> <span class="ss">:articles</span> <span class="k">do</span> <span class="n">concerns</span> <span class="ss">:commentable</span> <span class="n">concerns</span> <span class="ss">:image_attachable</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="namespace :messages do concerns :commentable end namespace :articles do concerns :commentable concerns :image_attachable end ">Copy</button> </div> <h3 id="creating-paths-and-urls-from-objects"><a class="anchorlink" href="#creating-paths-and-urls-from-objects" data-turbo="false"><span>2.9</span> Creating Paths and URLs from Objects</a></h3><p>In addition to using the routing helpers, Rails can also create paths and URLs from an array of parameters. For example, suppose you have this set of routes:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:magazines</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:ads</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :magazines do resources :ads end ">Copy</button> </div> <p>When using <code>magazine_ad_path</code>, you can pass in instances of <code>Magazine</code> and <code>Ad</code> instead of the numeric IDs:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Ad details'</span><span class="p">,</span> <span class="n">magazine_ad_path</span><span class="p">(</span><span class="vi">@magazine</span><span class="p">,</span> <span class="vi">@ad</span><span class="p">)</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %> ">Copy</button> </div> <p>The generated path will be something like <code>/magazines/5/ads/42</code>.</p><p>You can also use <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionView/RoutingUrlFor.html#method-i-url_for"><code>url_for</code></a> with an array of objects to get the above path, like this:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Ad details'</span><span class="p">,</span> <span class="n">url_for</span><span class="p">([</span><span class="vi">@magazine</span><span class="p">,</span> <span class="vi">@ad</span><span class="p">])</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'Ad details', url_for([@magazine, @ad]) %> ">Copy</button> </div> <p>In this case, Rails will see that <code>@magazine</code> is a <code>Magazine</code> and <code>@ad</code> is an <code>Ad</code> and will therefore use the <code>magazine_ad_path</code> helper. An even shorter way to write that <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to"><code>link_to</code></a> is to specify just the object instead of the full <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/UrlFor.html"><code>url_for</code></a> call:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Ad details'</span><span class="p">,</span> <span class="p">[</span><span class="vi">@magazine</span><span class="p">,</span> <span class="vi">@ad</span><span class="p">]</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'Ad details', [@magazine, @ad] %> ">Copy</button> </div> <p>If you wanted to link to just a magazine:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Magazine details'</span><span class="p">,</span> <span class="vi">@magazine</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'Magazine details', @magazine %> ">Copy</button> </div> <p>For other actions, you need to insert the action name as the first element of the array, for <code>edit_magazine_ad_path</code>:</p><div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">link_to</span> <span class="s1">'Edit Ad'</span><span class="p">,</span> <span class="p">[</span><span class="ss">:edit</span><span class="p">,</span> <span class="vi">@magazine</span><span class="p">,</span> <span class="vi">@ad</span><span class="p">]</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %> ">Copy</button> </div> <p>This allows you to treat instances of your models as URLs, and is a key advantage to using the resourceful style.</p><div class="interstitial note"><p>In order to automatically derive paths and URLs from objects such as <code>[@magazine, @ad]</code>, Rails uses methods from <a href="https://api.rubyonrails.org/v8.0.0/classes/ActiveModel/Naming.html"><code>ActiveModel::Naming</code></a> and <a href="https://api.rubyonrails.org/v8.0.0/classes/ActiveModel/Conversion.html"><code>ActiveModel::Conversion</code></a> modules. Specifically, the <code>@magazine.model_name.route_key</code> returns <code>magazines</code> and <code>@magazine.to_param</code> returns a string representation of the model's <code>id</code>. So the generated path may be something like <code>/magazines/1/ads/42</code> for the objects <code>[@magazine, @ad]</code>.</p></div><h3 id="adding-more-restful-routes"><a class="anchorlink" href="#adding-more-restful-routes" data-turbo="false"><span>2.10</span> Adding More RESTful Routes</a></h3><p>You are not limited to the <a href="#crud-verbs-and-actions">seven routes</a> that RESTful routing creates by default. You can add additional routes that apply to the collection or individual members of the collection.</p><p>The below sections describe adding member routes and collection routes. The term <code>member</code> refers to routes acting on a single element, such as <code>show</code>, <code>update</code>, or <code>destroy</code>. The term <code>collection</code> refers to routes acting on multiple, or a collection of, elements, such as the <code>index</code> route.</p><h4 id="adding-member-routes"><a class="anchorlink" href="#adding-member-routes" data-turbo="false"><span>2.10.1</span> Adding Member Routes</a></h4><p>You can add a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-member"><code>member</code></a> block into the resource block like this:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> <span class="k">do</span> <span class="n">member</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"preview"</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos do member do get "preview" end end ">Copy</button> </div> <p>An incoming GET request to <code>/photos/1/preview</code> will route to the <code>preview</code> action of <code>PhotosController</code>. The resource id value will be available in <code>params[:id]</code>. It will also create the <code>preview_photo_url</code> and <code>preview_photo_path</code> helpers.</p><p>Within the <code>member</code> block, each route definition specifies the HTTP verb (<code>get</code> in the above example with <code>get 'preview'</code>). In addition to <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-get"><code>get</code></a>, you can use <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-patch"><code>patch</code></a>, <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-put"><code>put</code></a>, <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-post"><code>post</code></a>, or <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-delete"><code>delete</code></a>.</p><p>If you don't have multiple <code>member</code> routes, you can also pass <code>:on</code> to a route, eliminating the block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"preview"</span><span class="p">,</span> <span class="ss">on: :member</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos do get "preview", on: :member end ">Copy</button> </div> <p>You can also leave out the <code>:on</code> option, this will create the same member route except that the resource id value will be available in <code>params[:photo_id]</code> instead of <code>params[:id]</code>. Route helpers will also be renamed from <code>preview_photo_url</code> and <code>preview_photo_path</code> to <code>photo_preview_url</code> and <code>photo_preview_path</code>.</p><h4 id="adding-collection-routes"><a class="anchorlink" href="#adding-collection-routes" data-turbo="false"><span>2.10.2</span> Adding Collection Routes</a></h4><p>To add a route to the collection, use a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-collection"><code>collection</code></a> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> <span class="k">do</span> <span class="n">collection</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"search"</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos do collection do get "search" end end ">Copy</button> </div> <p>This will enable Rails to recognize paths such as <code>/photos/search</code> with GET, and route to the <code>search</code> action of <code>PhotosController</code>. It will also create the <code>search_photos_url</code> and <code>search_photos_path</code> route helpers.</p><p>Just as with member routes, you can pass <code>:on</code> to a route:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"search"</span><span class="p">,</span> <span class="ss">on: :collection</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos do get "search", on: :collection end ">Copy</button> </div> <div class="interstitial note"><p>If you're defining additional resource routes with a symbol as the first positional argument, be mindful that it is not equivalent to using a string. Symbols infer controller actions while strings infer paths.</p></div><h4 id="adding-routes-for-additional-new-actions"><a class="anchorlink" href="#adding-routes-for-additional-new-actions" data-turbo="false"><span>2.10.3</span> Adding Routes for Additional New Actions</a></h4><p>To add an alternate new action using the <code>:on</code> shortcut:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:comments</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"preview"</span><span class="p">,</span> <span class="ss">on: :new</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :comments do get "preview", on: :new end ">Copy</button> </div> <p>This will enable Rails to recognize paths such as <code>/comments/new/preview</code> with GET, and route to the <code>preview</code> action of <code>CommentsController</code>. It will also create the <code>preview_new_comment_url</code> and <code>preview_new_comment_path</code> route helpers.</p><div class="interstitial info"><p>If you find yourself adding many extra actions to a resourceful route, it's time to stop and ask yourself whether you're disguising the presence of another resource.</p></div><p>It is possible to customize the default routes and helpers generated by <code>resources</code>, see <a href="#customizing-resourceful-routes">customizing resourceful routes section</a> for more.</p><h2 id="non-resourceful-routes"><a class="anchorlink" href="#non-resourceful-routes" data-turbo="false"><span>3</span> Non-Resourceful Routes</a></h2><p>In addition to resourceful routing with <code>resources</code>, Rails has powerful support for routing arbitrary URLs to actions. You don't get groups of routes automatically generated by resourceful routing. Instead, you set up each route separately within your application.</p><p>While you should usually use resourceful routing, there are places where non-resourceful routing is more appropriate. There's no need to try to force every last piece of your application into a resourceful framework if that's not a good fit.</p><p>One example use case for non-resourceful routing is mapping existing legacy URLs to new Rails actions.</p><h3 id="bound-parameters"><a class="anchorlink" href="#bound-parameters" data-turbo="false"><span>3.1</span> Bound Parameters</a></h3><p>When you set up a regular route, you supply a series of symbols that Rails maps to parts of an incoming HTTP request. For example, consider this route:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos(/:id)"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#display"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos(/:id)", to: "photos#display" ">Copy</button> </div> <p>If an incoming <code>GET</code> request of <code>/photos/1</code> is processed by this route, then the result will be to invoke the <code>display</code> action of the <code>PhotosController</code>, and to make the final parameter <code>"1"</code> available as <code>params[:id]</code>. This route will also route the incoming request of <code>/photos</code> to <code>PhotosController#display</code>, since <code>:id</code> is an optional parameter, denoted by parentheses in the above example.</p><h3 id="dynamic-segments"><a class="anchorlink" href="#dynamic-segments" data-turbo="false"><span>3.2</span> Dynamic Segments</a></h3><p>You can set up as many dynamic segments within a regular route as you like. Any segment will be available to the action as part of <code>params</code>. If you set up this route:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id/:user_id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id/:user_id", to: "photos#show" ">Copy</button> </div> <p>This route will respond to paths such as <code>/photos/1/2</code>. The <code>params</code> hash will be { controller: 'photos', action: 'show', id: '1', user_id: '2' }.</p><div class="interstitial info"><p>By default, dynamic segments don't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within a dynamic segment, add a constraint that overrides this – for example, <code>id: /[^\/]+/</code> allows anything except a slash.</p></div><h3 id="static-segments"><a class="anchorlink" href="#static-segments" data-turbo="false"><span>3.3</span> Static Segments</a></h3><p>You can specify static segments when creating a route by not prepending a colon to a segment:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id/with_user/:user_id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id/with_user/:user_id", to: "photos#show" ">Copy</button> </div> <p>This route would respond to paths such as <code>/photos/1/with_user/2</code>. In this case, <code>params</code> would be <code>{ controller: 'photos', action: 'show', id: '1', user_id: '2' }</code>.</p><h3 id="the-query-string"><a class="anchorlink" href="#the-query-string" data-turbo="false"><span>3.4</span> The Query String</a></h3><p>The <code>params</code> will also include any parameters from the query string. For example, with this route:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id", to: "photos#show" ">Copy</button> </div> <p>An incoming <code>GET</code> request for <code>/photos/1?user_id=2</code> will be dispatched to the <code>show</code> action of the <code>PhotosController</code> class as usual and the <code>params</code> hash will be <code>{ controller: 'photos', action: 'show', id: '1', user_id: '2' }</code>.</p><h3 id="defining-default-parameters"><a class="anchorlink" href="#defining-default-parameters" data-turbo="false"><span>3.5</span> Defining Default Parameters</a></h3><p>You can define defaults in a route by supplying a hash for the <code>:defaults</code> option. This even applies to parameters that you do not specify as dynamic segments. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span><span class="p">,</span> <span class="ss">defaults: </span><span class="p">{</span> <span class="ss">format: </span><span class="s2">"jpg"</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id", to: "photos#show", defaults: { format: "jpg" } ">Copy</button> </div> <p>Rails would match <code>photos/12</code> to the <code>show</code> action of <code>PhotosController</code>, and set <code>params[:format]</code> to <code>"jpg"</code>.</p><p>You can also use a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-defaults"><code>defaults</code></a> block to define the defaults for multiple items:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">defaults</span> <span class="ss">format: :json</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="defaults format: :json do resources :photos resources :articles end ">Copy</button> </div> <div class="interstitial note"><p>You cannot override defaults via query parameters - this is for security reasons. The only defaults that can be overridden are dynamic segments via substitution in the URL path.</p></div><h3 id="naming-routes"><a class="anchorlink" href="#naming-routes" data-turbo="false"><span>3.6</span> Naming Routes</a></h3><p>You can specify a name that will used by the <code>_path</code> and <code>_url</code> helpers for any route using the <code>:as</code> option:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"exit"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"sessions#destroy"</span><span class="p">,</span> <span class="ss">as: :logout</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "exit", to: "sessions#destroy", as: :logout ">Copy</button> </div> <p>This will create <code>logout_path</code> and <code>logout_url</code> as the route helpers in your application. Calling <code>logout_path</code> will return <code>/exit</code>.</p><p>You can also use <code>as</code> to override routing helper names defined by <code>resources</code> by placing a custom route definition <em>before</em> the resource is defined, like this:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">":username"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"users#show"</span><span class="p">,</span> <span class="ss">as: :user</span> <span class="n">resources</span> <span class="ss">:users</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get ":username", to: "users#show", as: :user resources :users ">Copy</button> </div> <p>This will define a <code>user_path</code> helper that will match <code>/:username</code> (e.g. <code>/jane</code>). Inside the <code>show</code> action of <code>UsersController</code>, <code>params[:username]</code> will contain the username for the user.</p><h3 id="http-verb-constraints"><a class="anchorlink" href="#http-verb-constraints" data-turbo="false"><span>3.7</span> HTTP Verb Constraints</a></h3><p>In general, you should use the <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-get"><code>get</code></a>, <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-post"><code>post</code></a>, <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-put"><code>put</code></a>, <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-patch"><code>patch</code></a>, and <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/HttpHelpers.html#method-i-delete"><code>delete</code></a> methods to constrain a route to a particular verb. There is a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-match"><code>match</code></a> method that you could use with the <code>:via</code> option to match multiple verbs at once:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">match</span> <span class="s2">"photos"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span><span class="p">,</span> <span class="ss">via: </span><span class="p">[</span><span class="ss">:get</span><span class="p">,</span> <span class="ss">:post</span><span class="p">]</span> </code></pre> <button class="clipboard-button" data-clipboard-text="match "photos", to: "photos#show", via: [:get, :post] ">Copy</button> </div> <p>The above route matches GET and POST requests to the <code>show</code> action of the <code>PhotosController</code>.</p><p>You can match all verbs to a particular route using <code>via: :all</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">match</span> <span class="s2">"photos"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span><span class="p">,</span> <span class="ss">via: :all</span> </code></pre> <button class="clipboard-button" data-clipboard-text="match "photos", to: "photos#show", via: :all ">Copy</button> </div> <div class="interstitial note"><p>Routing both <code>GET</code> and <code>POST</code> requests to a single action has security implications. For example, the <code>GET</code> action won't check for CSRF token (so writing to the database from <code>GET</code> request is not a good idea. For more information see the <a href="security.html#csrf-countermeasures">security guide</a>). In general, avoid routing all verbs to a single action unless you have a good reason.</p></div><h3 id="segment-constraints"><a class="anchorlink" href="#segment-constraints" data-turbo="false"><span>3.8</span> Segment Constraints</a></h3><p>You can use the <code>:constraints</code> option to enforce a format for a dynamic segment:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">id: </span><span class="sr">/[A-Z]\d{5}/</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id", to: "photos#show", constraints: { id: /[A-Z]\d{5}/ } ">Copy</button> </div> <p>The above route definition requires <code>id</code> to be 5 alphanumeric characters long. Therefore, this route would match paths such as <code>/photos/A12345</code>, but not <code>/photos/893</code>. You can more succinctly express the same route this way:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#show"</span><span class="p">,</span> <span class="ss">id: </span><span class="sr">/[A-Z]\d{5}/</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/:id", to: "photos#show", id: /[A-Z]\d{5}/ ">Copy</button> </div> <p>The <code>:constraints</code> option takes regular expressions (as well as any object that responds to <code>matches?</code> method) with the restriction that regexp anchors can't be used. For example, the following route will not work:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"articles#show"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">id: </span><span class="sr">/^\d/</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/:id", to: "articles#show", constraints: { id: /^\d/ } ">Copy</button> </div> <p>However, note that you don't need to use anchors because all routes are anchored at the start and the end.</p><p>For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/:id"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"articles#show"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">id: </span><span class="sr">/\d.+/</span> <span class="p">}</span> <span class="n">get</span> <span class="s2">"/:username"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"users#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/:id", to: "articles#show", constraints: { id: /\d.+/ } get "/:username", to: "users#show" ">Copy</button> </div> <p>The above routes would allow sharing the root namespace and:</p> <ul> <li>route paths that always begin with a number, like <code>/1-hello-world</code>, to <code>articles</code> with <code>id</code> value.</li> <li>route paths that never begin with a number, like <code>/david</code>, to <code>users</code> with <code>username</code> value.</li> </ul> <h3 id="request-based-constraints"><a class="anchorlink" href="#request-based-constraints" data-turbo="false"><span>3.9</span> Request-Based Constraints</a></h3><p>You can also constrain a route based on any method on the <a href="action_controller_overview.html#the-request-object">Request object</a> that returns a <code>String</code>.</p><p>You specify a request-based constraint the same way that you specify a segment constraint. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#index"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">subdomain: </span><span class="s2">"admin"</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos", to: "photos#index", constraints: { subdomain: "admin" } ">Copy</button> </div> <p>Will match an incoming request with a path to <code>admin</code> subdomain.</p><p>You can also specify constraints by using a <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Scoping.html#method-i-constraints"><code>constraints</code></a> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">namespace</span> <span class="ss">:admin</span> <span class="k">do</span> <span class="n">constraints</span> <span class="ss">subdomain: </span><span class="s2">"admin"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="namespace :admin do constraints subdomain: "admin" do resources :photos end end ">Copy</button> </div> <p>Will match something like <code>https://admin.example.com/photos</code>.</p><p>Request constraints work by calling a method on the <a href="action_controller_overview.html#the-request-object">Request object</a> with the same name as the hash key and then comparing the return value with the hash value. For example: <code>constraints: { subdomain: 'api' }</code> will match an <code>api</code> subdomain as expected. However, using a symbol <code>constraints: { subdomain: :api }</code> will not, because <code>request.subdomain</code> returns <code>'api'</code> as a String.</p><div class="interstitial note"><p>Constraint values should match the corresponding Request object method return type.</p></div><p>There is an exception for the <code>format</code> constraint, while it's a method on the Request object, it's also an implicit optional parameter on every path. Segment constraints take precedence and the <code>format</code> constraint is only applied when enforced through a hash. For example, <code>get 'foo', constraints: { format: 'json' }</code> will match <code>GET /foo</code> because the format is optional by default.</p><div class="interstitial note"><p>You can <a href="#advanced-constraints">use a lambda</a> like in <code>get 'foo', constraints: lambda { |req| req.format == :json }</code> to only match the route to explicit JSON requests.</p></div><h3 id="advanced-constraints"><a class="anchorlink" href="#advanced-constraints" data-turbo="false"><span>3.10</span> Advanced Constraints</a></h3><p>If you have a more advanced constraint, you can provide an object that responds to <code>matches?</code> that Rails should use. Let's say you wanted to route all users on a restricted list to the <code>RestrictedListController</code>. You could do:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">RestrictedListConstraint</span> <span class="k">def</span> <span class="nf">initialize</span> <span class="vi">@ips</span> <span class="o">=</span> <span class="no">RestrictedList</span><span class="p">.</span><span class="nf">retrieve_ips</span> <span class="k">end</span> <span class="k">def</span> <span class="nf">matches?</span><span class="p">(</span><span class="n">request</span><span class="p">)</span> <span class="vi">@ips</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="nf">remote_ip</span><span class="p">)</span> <span class="k">end</span> <span class="k">end</span> <span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"*path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"restricted_list#index"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="no">RestrictedListConstraint</span><span class="p">.</span><span class="nf">new</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class RestrictedListConstraint def initialize @ips = RestrictedList.retrieve_ips end def matches?(request) @ips.include?(request.remote_ip) end end Rails.application.routes.draw do get "*path", to: "restricted_list#index", constraints: RestrictedListConstraint.new end ">Copy</button> </div> <p>You can also specify constraints as a lambda:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"*path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"restricted_list#index"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">request</span><span class="o">|</span> <span class="no">RestrictedList</span><span class="p">.</span><span class="nf">retrieve_ips</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="nf">remote_ip</span><span class="p">)</span> <span class="p">}</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="Rails.application.routes.draw do get "*path", to: "restricted_list#index", constraints: lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) } end ">Copy</button> </div> <p>Both the <code>matches?</code> method and the lambda gets the <code>request</code> object as an argument.</p><h4 id="constraints-in-a-block-form"><a class="anchorlink" href="#constraints-in-a-block-form" data-turbo="false"><span>3.10.1</span> Constraints in a Block Form</a></h4><p>You can specify constraints in a block form. This is useful for when you need to apply the same rule to several routes. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">RestrictedListConstraint</span> <span class="c1"># ...Same as the example above</span> <span class="k">end</span> <span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">constraints</span><span class="p">(</span><span class="no">RestrictedListConstraint</span><span class="p">.</span><span class="nf">new</span><span class="p">)</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"*path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"restricted_list#index"</span> <span class="n">get</span> <span class="s2">"*other-path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"other_restricted_list#index"</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class RestrictedListConstraint # ...Same as the example above end Rails.application.routes.draw do constraints(RestrictedListConstraint.new) do get "*path", to: "restricted_list#index" get "*other-path", to: "other_restricted_list#index" end end ">Copy</button> </div> <p>You can also use a <code>lambda</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">constraints</span><span class="p">(</span><span class="nb">lambda</span> <span class="p">{</span> <span class="o">|</span><span class="n">request</span><span class="o">|</span> <span class="no">RestrictedList</span><span class="p">.</span><span class="nf">retrieve_ips</span><span class="p">.</span><span class="nf">include?</span><span class="p">(</span><span class="n">request</span><span class="p">.</span><span class="nf">remote_ip</span><span class="p">)</span> <span class="p">})</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"*path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"restricted_list#index"</span> <span class="n">get</span> <span class="s2">"*other-path"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"other_restricted_list#index"</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="Rails.application.routes.draw do constraints(lambda { |request| RestrictedList.retrieve_ips.include?(request.remote_ip) }) do get "*path", to: "restricted_list#index" get "*other-path", to: "other_restricted_list#index" end end ">Copy</button> </div> <h3 id="wildcard-segments"><a class="anchorlink" href="#wildcard-segments" data-turbo="false"><span>3.11</span> Wildcard Segments</a></h3><p>A route definition can have a wildcard segment, which is a segment prefixed with a star, such as <code>*other</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"photos/*other"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"photos#unknown"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "photos/*other", to: "photos#unknown" ">Copy</button> </div> <p>Wildcard segments allow for something called "route globbing", which is a way to specify that a particular parameter (<code>*other</code> above) be matched to the remaining part of a route.</p><p>So the above route would match <code>photos/12</code> or <code>/photos/long/path/to/12</code>, setting <code>params[:other]</code> to <code>"12"</code> or <code>"long/path/to/12"</code>.</p><p>Wildcard segments can occur anywhere in a route. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"books/*section/:title"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"books#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "books/*section/:title", to: "books#show" ">Copy</button> </div> <p>would match <code>books/some/section/last-words-a-memoir</code> with <code>params[:section]</code> equals <code>'some/section'</code>, and <code>params[:title]</code> equals <code>'last-words-a-memoir'</code>.</p><p>Technically, a route can have even more than one wildcard segment. The matcher assigns segments to parameters in the order they occur. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"*a/foo/*b"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"test#index"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "*a/foo/*b", to: "test#index" ">Copy</button> </div> <p>would match <code>zoo/woo/foo/bar/baz</code> with <code>params[:a]</code> equals <code>'zoo/woo'</code>, and <code>params[:b]</code> equals <code>'bar/baz'</code>.</p><h3 id="format-segments"><a class="anchorlink" href="#format-segments" data-turbo="false"><span>3.12</span> Format Segments</a></h3><p>Given this route definition:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"*pages"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"pages#show"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "*pages", to: "pages#show" ">Copy</button> </div> <p>By requesting <code>'/foo/bar.json'</code>, your <code>params[:pages]</code> will be equal to <code>'foo/bar'</code> with the request format of JSON in <code>params[:format]</code>.</p><p>The default behavior with <code>format</code> is that if included Rails automatically captures it from the URL and includes it in params[:format], but <code>format</code> is not required in a URL.</p><p>If you want to match URLs without an explicit format and ignore URLs that include a format extension, you could supply <code>format: false</code> like this:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"*pages"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"pages#show"</span><span class="p">,</span> <span class="ss">format: </span><span class="kp">false</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "*pages", to: "pages#show", format: false ">Copy</button> </div> <p>If you want to make the format segment mandatory, so it cannot be omitted, you can supply <code>format: true</code> like this:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"*pages"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"pages#show"</span><span class="p">,</span> <span class="ss">format: </span><span class="kp">true</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "*pages", to: "pages#show", format: true ">Copy</button> </div> <h3 id="redirection"><a class="anchorlink" href="#redirection" data-turbo="false"><span>3.13</span> Redirection</a></h3><p>You can redirect any path to any other path by using the <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Redirection.html#method-i-redirect"><code>redirect</code></a> helper in your router:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/stories"</span><span class="p">,</span> <span class="ss">to: </span><span class="n">redirect</span><span class="p">(</span><span class="s2">"/articles"</span><span class="p">)</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/stories", to: redirect("/articles") ">Copy</button> </div> <p>You can also reuse dynamic segments from the match in the path to redirect to:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/stories/:name"</span><span class="p">,</span> <span class="ss">to: </span><span class="n">redirect</span><span class="p">(</span><span class="s2">"/articles/%{name}"</span><span class="p">)</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/stories/:name", to: redirect("/articles/%{name}") ">Copy</button> </div> <p>You can also provide a block to <code>redirect</code>, which receives the symbolized path parameters and the request object:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/stories/:name"</span><span class="p">,</span> <span class="ss">to: </span><span class="n">redirect</span> <span class="p">{</span> <span class="o">|</span><span class="n">path_params</span><span class="p">,</span> <span class="n">req</span><span class="o">|</span> <span class="s2">"/articles/</span><span class="si">#{</span><span class="n">path_params</span><span class="p">[</span><span class="ss">:name</span><span class="p">].</span><span class="nf">pluralize</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span> <span class="n">get</span> <span class="s2">"/stories"</span><span class="p">,</span> <span class="ss">to: </span><span class="n">redirect</span> <span class="p">{</span> <span class="o">|</span><span class="n">path_params</span><span class="p">,</span> <span class="n">req</span><span class="o">|</span> <span class="s2">"/articles/</span><span class="si">#{</span><span class="n">req</span><span class="p">.</span><span class="nf">subdomain</span><span class="si">}</span><span class="s2">"</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/stories/:name", to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" } get "/stories", to: redirect { |path_params, req| "/articles/#{req.subdomain}" } ">Copy</button> </div> <p>Please note that default redirection is a 301 "Moved Permanently" redirect. Keep in mind that some web browsers or proxy servers will cache this type of redirect, making the old page inaccessible. You can use the <code>:status</code> option to change the response status:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"/stories/:name"</span><span class="p">,</span> <span class="ss">to: </span><span class="n">redirect</span><span class="p">(</span><span class="s2">"/articles/%{name}"</span><span class="p">,</span> <span class="ss">status: </span><span class="mi">302</span><span class="p">)</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "/stories/:name", to: redirect("/articles/%{name}", status: 302) ">Copy</button> </div> <p>In all of these cases, if you don't provide the host (<code>http://www.example.com</code>), Rails will take those details from the current request.</p><h3 id="routing-to-rack-applications"><a class="anchorlink" href="#routing-to-rack-applications" data-turbo="false"><span>3.14</span> Routing to Rack Applications</a></h3><p>Instead of specifying <code>:to</code> as a String like <code>'articles#index'</code>, which corresponds to the <code>index</code> method in the <code>ArticlesController</code> class, you can specify any <a href="rails_on_rack.html">Rack application</a> as the endpoint for a matcher:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">match</span> <span class="s2">"/application.js"</span><span class="p">,</span> <span class="ss">to: </span><span class="no">MyRackApp</span><span class="p">,</span> <span class="ss">via: :all</span> </code></pre> <button class="clipboard-button" data-clipboard-text="match "/application.js", to: MyRackApp, via: :all ">Copy</button> </div> <p>As long as <code>MyRackApp</code> responds to <code>call</code> and returns a <code>[status, headers, body]</code>, the router won't know the difference between the Rack application and a controller action. This is an appropriate use of <code>via: :all</code>, as you will want to allow your Rack application to handle all verbs.</p><div class="interstitial note"><p>An interesting tidbit - <code>'articles#index'</code> expands out to <code>ArticlesController.action(:index)</code>, which returns a valid Rack application.</p></div><div class="interstitial note"><p>Since procs/lambdas are objects that respond to <code>call</code>, you can implement very simple routes (e.g. for health checks) inline, something like: <code>get '/health', to: ->(env) { [204, {}, ['']] }</code></p></div><p>If you specify a Rack application as the endpoint for a matcher, remember that the route will be unchanged in the receiving application. With the following route your Rack application should expect the route to be <code>/admin</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">match</span> <span class="s2">"/admin"</span><span class="p">,</span> <span class="ss">to: </span><span class="no">AdminApp</span><span class="p">,</span> <span class="ss">via: :all</span> </code></pre> <button class="clipboard-button" data-clipboard-text="match "/admin", to: AdminApp, via: :all ">Copy</button> </div> <p>If you would prefer to have your Rack application receive requests at the root path instead, use <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Base.html#method-i-mount"><code>mount</code></a>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">mount</span> <span class="no">AdminApp</span><span class="p">,</span> <span class="ss">at: </span><span class="s2">"/admin"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="mount AdminApp, at: "/admin" ">Copy</button> </div> <h3 id="using-root"><a class="anchorlink" href="#using-root" data-turbo="false"><span>3.15</span> Using <code>root</code></a></h3><p>You can specify what Rails should route <code>'/'</code> to with the <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-root"><code>root</code></a> method:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">root</span> <span class="ss">to: </span><span class="s2">"pages#main"</span> <span class="n">root</span> <span class="s2">"pages#main"</span> <span class="c1"># shortcut for the above</span> </code></pre> <button class="clipboard-button" data-clipboard-text="root to: "pages#main" root "pages#main" # shortcut for the above ">Copy</button> </div> <p>You typically put the <code>root</code> route at the top of the file so that it can be matched first.</p><div class="interstitial note"><p>The <code>root</code> route primarily handles <code>GET</code> requests by default. But it is possible to configure it to handle other verbs (e.g. <code>root "posts#index", via: :post</code>)</p></div><p>You can also use root inside namespaces and scopes as well:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">root</span> <span class="ss">to: </span><span class="s2">"home#index"</span> <span class="n">namespace</span> <span class="ss">:admin</span> <span class="k">do</span> <span class="n">root</span> <span class="ss">to: </span><span class="s2">"admin#index"</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="root to: "home#index" namespace :admin do root to: "admin#index" end ">Copy</button> </div> <p>The above will match <code>/admin</code> to the <code>index</code> action for the <code>AdminController</code> and match <code>/</code> to <code>index</code> action of the <code>HomeController</code>.</p><h3 id="unicode-character-routes"><a class="anchorlink" href="#unicode-character-routes" data-turbo="false"><span>3.16</span> Unicode Character Routes</a></h3><p>You can specify unicode character routes directly. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">get</span> <span class="s2">"こんにちは"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"welcome#index"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="get "こんにちは", to: "welcome#index" ">Copy</button> </div> <h3 id="direct-routes"><a class="anchorlink" href="#direct-routes" data-turbo="false"><span>3.17</span> Direct Routes</a></h3><p>You can create custom URL helpers by calling <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/CustomUrls.html#method-i-direct"><code>direct</code></a>. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">direct</span> <span class="ss">:homepage</span> <span class="k">do</span> <span class="s2">"https://rubyonrails.org"</span> <span class="k">end</span> <span class="c1"># >> homepage_url</span> <span class="c1"># => "https://rubyonrails.org"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="direct :homepage do "https://rubyonrails.org" end # >> homepage_url # => "https://rubyonrails.org" ">Copy</button> </div> <p>The return value of the block must be a valid argument for the <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/UrlFor.html"><code>url_for</code></a> method. So, you can pass a valid string URL, Hash, Array, an Active Model instance, or an Active Model class.</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">direct</span> <span class="ss">:commentable</span> <span class="k">do</span> <span class="o">|</span><span class="n">model</span><span class="o">|</span> <span class="p">[</span> <span class="n">model</span><span class="p">,</span> <span class="ss">anchor: </span><span class="n">model</span><span class="p">.</span><span class="nf">dom_id</span> <span class="p">]</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="direct :commentable do |model| [ model, anchor: model.dom_id ] end ">Copy</button> </div> <div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">direct</span> <span class="ss">:main</span> <span class="k">do</span> <span class="p">{</span> <span class="ss">controller: </span><span class="s2">"pages"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"index"</span><span class="p">,</span> <span class="ss">subdomain: </span><span class="s2">"www"</span> <span class="p">}</span> <span class="k">end</span> <span class="c1"># >> main_url</span> <span class="c1"># => "http://www.example.com/pages"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="direct :main do { controller: "pages", action: "index", subdomain: "www" } end # >> main_url # => "http://www.example.com/pages" ">Copy</button> </div> <h3 id="using-resolve"><a class="anchorlink" href="#using-resolve" data-turbo="false"><span>3.18</span> Using <code>resolve</code></a></h3><p>The <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/CustomUrls.html#method-i-resolve"><code>resolve</code></a> method allows customizing polymorphic mapping of models. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resource</span> <span class="ss">:basket</span> <span class="n">resolve</span><span class="p">(</span><span class="s2">"Basket"</span><span class="p">)</span> <span class="p">{</span> <span class="p">[</span><span class="ss">:basket</span><span class="p">]</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resource :basket resolve("Basket") { [:basket] } ">Copy</button> </div> <div class="interstitial code"> <pre><code class="highlight erb"><span class="cp"><%=</span> <span class="n">form_with</span> <span class="ss">model: </span><span class="vi">@basket</span> <span class="k">do</span> <span class="o">|</span><span class="n">form</span><span class="o">|</span> <span class="cp">%></span> <span class="c"><!-- basket form --></span> <span class="cp"><%</span> <span class="k">end</span> <span class="cp">%></span> </code></pre> <button class="clipboard-button" data-clipboard-text="<%= form_with model: @basket do |form| %> <!-- basket form --> <% end %> ">Copy</button> </div> <p>This will generate the singular URL <code>/basket</code> instead of the usual <code>/baskets/:id</code>.</p><h2 id="customizing-resourceful-routes"><a class="anchorlink" href="#customizing-resourceful-routes" data-turbo="false"><span>4</span> Customizing Resourceful Routes</a></h2><p>While the default routes and helpers generated by <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-resources"><code>resources</code></a> will usually serve you well, you may need to customize them in some way. Rails allows for several different ways to customize the resourceful routes and helpers. This section will detail the available options.</p><h3 id="specifying-a-controller-to-use"><a class="anchorlink" href="#specifying-a-controller-to-use" data-turbo="false"><span>4.1</span> Specifying a Controller to Use</a></h3><p>The <code>:controller</code> option lets you explicitly specify a controller to use for the resource. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">controller: </span><span class="s2">"images"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, controller: "images" ">Copy</button> </div> <p>will recognize incoming paths beginning with <code>/photos</code> but route to the <code>Images</code> controller:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/photos</td> <td>images#index</td> <td>photos_path</td> </tr> <tr> <td>GET</td> <td>/photos/new</td> <td>images#new</td> <td>new_photo_path</td> </tr> <tr> <td>POST</td> <td>/photos</td> <td>images#create</td> <td>photos_path</td> </tr> <tr> <td>GET</td> <td>/photos/:id</td> <td>images#show</td> <td>photo_path(:id)</td> </tr> <tr> <td>GET</td> <td>/photos/:id/edit</td> <td>images#edit</td> <td>edit_photo_path(:id)</td> </tr> <tr> <td>PATCH/PUT</td> <td>/photos/:id</td> <td>images#update</td> <td>photo_path(:id)</td> </tr> <tr> <td>DELETE</td> <td>/photos/:id</td> <td>images#destroy</td> <td>photo_path(:id)</td> </tr> </tbody></table></div> <p>For namespaced controllers you can use the directory notation. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:user_permissions</span><span class="p">,</span> <span class="ss">controller: </span><span class="s2">"admin/user_permissions"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :user_permissions, controller: "admin/user_permissions" ">Copy</button> </div> <p>This will route to the <code>Admin::UserPermissionsController</code> instance.</p><div class="interstitial note"><p>Only the directory notation is supported. Specifying the controller with Ruby constant notation (e.g. <code>controller: 'Admin::UserPermissions'</code>) is not supported.</p></div><h3 id="specifying-constraints-on-id"><a class="anchorlink" href="#specifying-constraints-on-id" data-turbo="false"><span>4.2</span> Specifying Constraints on <code>id</code></a></h3><p>You can use the <code>:constraints</code> option to specify a required format on the implicit <code>id</code>. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">id: </span><span class="sr">/[A-Z][A-Z][0-9]+/</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ } ">Copy</button> </div> <p>This declaration constrains the <code>:id</code> parameter to match the given regular expression. The router would no longer match <code>/photos/1</code> to this route. Instead, <code>/photos/RR27</code> would match.</p><p>You can specify a single constraint to apply to a number of routes by using the block form:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">constraints</span><span class="p">(</span><span class="ss">id: </span><span class="sr">/[A-Z][A-Z][0-9]+/</span><span class="p">)</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span> <span class="n">resources</span> <span class="ss">:accounts</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="constraints(id: /[A-Z][A-Z][0-9]+/) do resources :photos resources :accounts end ">Copy</button> </div> <div class="interstitial note"><p>You can use the more <a href="#advanced-constraints">advanced constraints</a> available in non-resourceful routes section in this context as well.</p></div><div class="interstitial info"><p>By default the <code>:id</code> parameter doesn't accept dots - this is because the dot is used as a separator for formatted routes. If you need to use a dot within an <code>:id</code> add a constraint which overrides this - for example <code>id: /[^\/]+/</code> allows anything except a slash.</p></div><h3 id="overriding-the-named-route-helpers"><a class="anchorlink" href="#overriding-the-named-route-helpers" data-turbo="false"><span>4.3</span> Overriding the Named Route Helpers</a></h3><p>The <code>:as</code> option lets you override the default naming for the route helpers. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"images"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, as: "images" ">Copy</button> </div> <p>This will match <code>/photos</code> and route the requests to <code>PhotosController</code> as usual, <em>but</em> use the value of the <code>:as</code> option to name the helpers <code>images_path</code> etc., as shown:</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/photos</td> <td>photos#index</td> <td>images_path</td> </tr> <tr> <td>GET</td> <td>/photos/new</td> <td>photos#new</td> <td>new_image_path</td> </tr> <tr> <td>POST</td> <td>/photos</td> <td>photos#create</td> <td>images_path</td> </tr> <tr> <td>GET</td> <td>/photos/:id</td> <td>photos#show</td> <td>image_path(:id)</td> </tr> <tr> <td>GET</td> <td>/photos/:id/edit</td> <td>photos#edit</td> <td>edit_image_path(:id)</td> </tr> <tr> <td>PATCH/PUT</td> <td>/photos/:id</td> <td>photos#update</td> <td>image_path(:id)</td> </tr> <tr> <td>DELETE</td> <td>/photos/:id</td> <td>photos#destroy</td> <td>image_path(:id)</td> </tr> </tbody></table></div> <h3 id="renaming-the-new-and-edit-path-names"><a class="anchorlink" href="#renaming-the-new-and-edit-path-names" data-turbo="false"><span>4.4</span> Renaming the <code>new</code> and <code>edit</code> Path Names</a></h3><p>The <code>:path_names</code> option lets you override the default <code>new</code> and <code>edit</code> segment in paths. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">path_names: </span><span class="p">{</span> <span class="ss">new: </span><span class="s2">"make"</span><span class="p">,</span> <span class="ss">edit: </span><span class="s2">"change"</span> <span class="p">}</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, path_names: { new: "make", edit: "change" } ">Copy</button> </div> <p>This would allow paths such as <code>/photos/make</code> and <code>/photos/1/change</code> instead of <code>/photos/new</code> and <code>/photos/1/edit</code>.</p><div class="interstitial note"><p>The route helpers and controller action names aren't changed by this option. The two paths shown would have <code>new_photo_path</code> and <code>edit_photo_path</code> helpers and still route to the <code>new</code> and <code>edit</code> actions.</p></div><p>It is also possible to change this option uniformly for all of your routes by using a <code>scope</code> block:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="ss">path_names: </span><span class="p">{</span> <span class="ss">new: </span><span class="s2">"make"</span> <span class="p">}</span> <span class="k">do</span> <span class="c1"># rest of your routes</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope path_names: { new: "make" } do # rest of your routes end ">Copy</button> </div> <h3 id="prefixing-the-named-route-helpers-with-as"><a class="anchorlink" href="#prefixing-the-named-route-helpers-with-as" data-turbo="false"><span>4.5</span> Prefixing the Named Route Helpers with <code>:as</code></a></h3><p>You can use the <code>:as</code> option to prefix the named route helpers that Rails generates for a route. Use this option to prevent name collisions between routes using a path scope. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="s2">"admin"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"admin_photos"</span> <span class="k">end</span> <span class="n">resources</span> <span class="ss">:photos</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope "admin" do resources :photos, as: "admin_photos" end resources :photos ">Copy</button> </div> <p>This changes the route helpers for <code>/admin/photos</code> from <code>photos_path</code>, <code>new_photos_path</code>, etc. to <code>admin_photos_path</code>, <code>new_admin_photo_path</code>, etc. Without the addition of <code>as: 'admin_photos'</code> on the scoped <code>resources :photos</code>, the non-scoped <code>resources :photos</code> will not have any route helpers.</p><p>To prefix a group of route helpers, use <code>:as</code> with <code>scope</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="s2">"admin"</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"admin"</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">:accounts</span> <span class="k">end</span> <span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">:accounts</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope "admin", as: "admin" do resources :photos, :accounts end resources :photos, :accounts ">Copy</button> </div> <p>Just as before, this changes the <code>/admin</code> scoped resource helpers to <code>admin_photos_path</code> and <code>admin_accounts_path</code>, and allows the non-scoped resources to use <code>photos_path</code> and <code>accounts_path</code>.</p><div class="interstitial note"><p>The <code>namespace</code> scope will automatically add <code>:as</code> as well as <code>:module</code> and <code>:path</code> prefixes.</p></div><h3 id="using-as-in-nested-resources"><a class="anchorlink" href="#using-as-in-nested-resources" data-turbo="false"><span>4.6</span> Using <code>:as</code> in Nested Resources</a></h3><p>The <code>:as</code> option can override routing helper names for resources in nested routes as well. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:magazines</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:ads</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"periodical_ads"</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :magazines do resources :ads, as: "periodical_ads" end ">Copy</button> </div> <p>This will create routing helpers such as <code>magazine_periodical_ads_url</code> and <code>edit_magazine_periodical_ad_path</code> instead of the default <code>magazine_ads_url</code> and <code>edit_magazine_ad_path</code>.</p><h3 id="parametric-scopes"><a class="anchorlink" href="#parametric-scopes" data-turbo="false"><span>4.7</span> Parametric Scopes</a></h3><p>You can prefix routes with a named parameter:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span> <span class="s2">":account_id"</span><span class="p">,</span> <span class="ss">as: </span><span class="s2">"account"</span><span class="p">,</span> <span class="ss">constraints: </span><span class="p">{</span> <span class="ss">account_id: </span><span class="sr">/\d+/</span> <span class="p">}</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:articles</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope ":account_id", as: "account", constraints: { account_id: /\d+/ } do resources :articles end ">Copy</button> </div> <p>This will provide you with paths such as <code>/1/articles/9</code> and will allow you to reference the <code>account_id</code> part of the path as <code>params[:account_id]</code> in controllers, helpers, and views.</p><p>It will also generate path and URL helpers prefixed with <code>account_</code>, into which you can pass your objects as expected:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">account_article_path</span><span class="p">(</span><span class="vi">@account</span><span class="p">,</span> <span class="vi">@article</span><span class="p">)</span> <span class="c1"># => /1/article/9</span> <span class="n">url_for</span><span class="p">([</span><span class="vi">@account</span><span class="p">,</span> <span class="vi">@article</span><span class="p">])</span> <span class="c1"># => /1/article/9</span> <span class="n">form_with</span><span class="p">(</span><span class="ss">model: </span><span class="p">[</span><span class="vi">@account</span><span class="p">,</span> <span class="vi">@article</span><span class="p">])</span> <span class="c1"># => <form action="/1/article/9" ...></span> </code></pre> <button class="clipboard-button" data-clipboard-text="account_article_path(@account, @article) # => /1/article/9 url_for([@account, @article]) # => /1/article/9 form_with(model: [@account, @article]) # => <form action="/1/article/9" ...> ">Copy</button> </div> <p>The <code>:as</code> option is also not mandatory, but without it, Rails will raise an error when evaluating <code>url_for([@account, @article])</code> or other helpers that rely on <code>url_for</code>, such as <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionView/Helpers/FormHelper.html#method-i-form_with"><code>form_with</code></a>.</p><h3 id="restricting-the-routes-created"><a class="anchorlink" href="#restricting-the-routes-created" data-turbo="false"><span>4.8</span> Restricting the Routes Created</a></h3><p>By default, using <code>resources</code> creates routes for the seven default actions (<code>index</code>, <code>show</code>, <code>new</code>, <code>create</code>, <code>edit</code>, <code>update</code>, and <code>destroy</code>). You can use the <code>:only</code> and <code>:except</code> options to limit which routes are created.</p><p>The <code>:only</code> option tells Rails to create only the specified routes:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">only: </span><span class="p">[</span><span class="ss">:index</span><span class="p">,</span> <span class="ss">:show</span><span class="p">]</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, only: [:index, :show] ">Copy</button> </div> <p>Now, a <code>GET</code> request to <code>/photos</code> or <code>/photos/:id</code> would succeed, but a <code>POST</code> request to <code>/photos</code> will fail to match.</p><p>The <code>:except</code> option specifies a route or list of routes that Rails should <em>not</em> create:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:photos</span><span class="p">,</span> <span class="ss">except: :destroy</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :photos, except: :destroy ">Copy</button> </div> <p>In this case, Rails will create all of the normal routes except the route for <code>destroy</code> (a <code>DELETE</code> request to <code>/photos/:id</code>).</p><div class="interstitial info"><p>If your application has many RESTful routes, using <code>:only</code> and <code>:except</code> to generate only the routes that you actually need can cut down on memory use and speed up the routing process by eliminating <a href="#listing-unused-routes">unused routed</a>.</p></div><h3 id="translated-paths"><a class="anchorlink" href="#translated-paths" data-turbo="false"><span>4.9</span> Translated Paths</a></h3><p>Using <code>scope</code>, we can alter path names generated by <code>resources</code>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">scope</span><span class="p">(</span><span class="ss">path_names: </span><span class="p">{</span> <span class="ss">new: </span><span class="s2">"neu"</span><span class="p">,</span> <span class="ss">edit: </span><span class="s2">"bearbeiten"</span> <span class="p">})</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:categories</span><span class="p">,</span> <span class="ss">path: </span><span class="s2">"kategorien"</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="scope(path_names: { new: "neu", edit: "bearbeiten" }) do resources :categories, path: "kategorien" end ">Copy</button> </div> <p>Rails now creates routes to the <code>CategoriesController</code>.</p> <div class="table-wrapper"><table><thead> <tr> <th>HTTP Verb</th> <th>Path</th> <th>Controller#Action</th> <th>Named Route Helper</th> </tr> </thead><tbody> <tr> <td>GET</td> <td>/kategorien</td> <td>categories#index</td> <td>categories_path</td> </tr> <tr> <td>GET</td> <td>/kategorien/neu</td> <td>categories#new</td> <td>new_category_path</td> </tr> <tr> <td>POST</td> <td>/kategorien</td> <td>categories#create</td> <td>categories_path</td> </tr> <tr> <td>GET</td> <td>/kategorien/:id</td> <td>categories#show</td> <td>category_path(:id)</td> </tr> <tr> <td>GET</td> <td>/kategorien/:id/bearbeiten</td> <td>categories#edit</td> <td>edit_category_path(:id)</td> </tr> <tr> <td>PATCH/PUT</td> <td>/kategorien/:id</td> <td>categories#update</td> <td>category_path(:id)</td> </tr> <tr> <td>DELETE</td> <td>/kategorien/:id</td> <td>categories#destroy</td> <td>category_path(:id)</td> </tr> </tbody></table></div> <h3 id="specifying-the-singular-form-of-a-resource"><a class="anchorlink" href="#specifying-the-singular-form-of-a-resource" data-turbo="false"><span>4.10</span> Specifying the Singular Form of a Resource</a></h3><p>If you need to override the singular form of a resource, you can add a rule to Active Support Inflector via <a href="https://api.rubyonrails.org/v8.0.0/classes/ActiveSupport/Inflector.html#method-i-inflections"><code>inflections</code></a>:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="no">ActiveSupport</span><span class="o">::</span><span class="no">Inflector</span><span class="p">.</span><span class="nf">inflections</span> <span class="k">do</span> <span class="o">|</span><span class="n">inflect</span><span class="o">|</span> <span class="n">inflect</span><span class="p">.</span><span class="nf">irregular</span> <span class="s2">"tooth"</span><span class="p">,</span> <span class="s2">"teeth"</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="ActiveSupport::Inflector.inflections do |inflect| inflect.irregular "tooth", "teeth" end ">Copy</button> </div> <h3 id="renaming-default-route-parameter-id"><a class="anchorlink" href="#renaming-default-route-parameter-id" data-turbo="false"><span>4.11</span> Renaming Default Route Parameter <code>id</code></a></h3><p>It is possible to rename the default parameter name <code>id</code> with the <code>:param</code> option. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">resources</span> <span class="ss">:videos</span><span class="p">,</span> <span class="ss">param: :identifier</span> </code></pre> <button class="clipboard-button" data-clipboard-text="resources :videos, param: :identifier ">Copy</button> </div> <p>Will now use <code>params[:identifier]</code> instead of <code>params[:id]</code>.</p><div class="interstitial code"> <pre><code class="highlight plaintext"> videos GET /videos(.:format) videos#index POST /videos(.:format) videos#create new_video GET /videos/new(.:format) videos#new edit_video GET /videos/:identifier/edit(.:format) videos#edit </code></pre> <button class="clipboard-button" data-clipboard-text=" videos GET /videos(.:format) videos#index POST /videos(.:format) videos#create new_video GET /videos/new(.:format) videos#new edit_video GET /videos/:identifier/edit(.:format) videos#edit ">Copy</button> </div> <div class="interstitial code"> <pre><code class="highlight ruby"><span class="no">Video</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">id: </span><span class="n">params</span><span class="p">[</span><span class="ss">:identifier</span><span class="p">])</span> <span class="c1"># Instead of</span> <span class="no">Video</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">id: </span><span class="n">params</span><span class="p">[</span><span class="ss">:id</span><span class="p">])</span> </code></pre> <button class="clipboard-button" data-clipboard-text="Video.find_by(id: params[:identifier]) # Instead of Video.find_by(id: params[:id]) ">Copy</button> </div> <p>You can override <a href="https://api.rubyonrails.org/v8.0.0/classes/ActiveRecord/Integration.html#method-i-to_param"><code>ActiveRecord::Base#to_param</code></a> of the associated model to construct a URL:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="k">class</span> <span class="nc">Video</span> <span class="o"><</span> <span class="no">ApplicationRecord</span> <span class="k">def</span> <span class="nf">to_param</span> <span class="n">identifier</span> <span class="k">end</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text="class Video < ApplicationRecord def to_param identifier end end ">Copy</button> </div> <div class="interstitial code"> <pre><code class="highlight irb"><span class="gp">irb></span><span class="w"> </span><span class="n">video</span> <span class="o">=</span> <span class="no">Video</span><span class="p">.</span><span class="nf">find_by</span><span class="p">(</span><span class="ss">identifier: </span><span class="s2">"Roman-Holiday"</span><span class="p">)</span> <span class="gp">irb></span><span class="w"> </span><span class="n">edit_video_path</span><span class="p">(</span><span class="n">video</span><span class="p">)</span> <span class="p">=></span> <span class="s2">"/videos/Roman-Holiday/edit"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="video = Video.find_by(identifier: "Roman-Holiday") edit_video_path(video) ">Copy</button> </div> <h2 id="inspecting-routes"><a class="anchorlink" href="#inspecting-routes" data-turbo="false"><span>5</span> Inspecting Routes</a></h2><p>Rails offers a few different ways of inspecting and testing your routes.</p><h3 id="listing-existing-routes"><a class="anchorlink" href="#listing-existing-routes" data-turbo="false"><span>5.1</span> Listing Existing Routes</a></h3><p>To get a complete list of routes available in an application, visit <code>http://localhost:3000/rails/info/routes</code> in the <strong>development</strong> environment. You can also execute the <code>bin/rails routes</code> command in your terminal to get the same output.</p><p>Both methods will list all of your routes, in the same order that they appear in <code>config/routes.rb</code>. For each route, you'll see:</p> <ul> <li>The route name (if any)</li> <li>The HTTP verb used (if the route doesn't respond to all verbs)</li> <li>The URL pattern to match</li> <li>The routing parameters for the route</li> </ul> <p>For example, here's a small section of the <code>bin/rails routes</code> output for a RESTful route:</p><div class="interstitial code"> <pre><code class="highlight plaintext"> users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit </code></pre> <button class="clipboard-button" data-clipboard-text=" users GET /users(.:format) users#index POST /users(.:format) users#create new_user GET /users/new(.:format) users#new edit_user GET /users/:id/edit(.:format) users#edit ">Copy</button> </div> <p>The route name (<code>new_user</code> above, for example) can be considered the base for deriving route helpers. To get the name of a route helper, add the suffix <code>_path</code> or <code>_url</code> to the route name (<code>new_user_path</code>, for example).</p><p>You can also use the <code>--expanded</code> option to turn on the expanded table formatting mode.</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">--expanded</span> <span class="go"> --[ Route 1 ]---------------------------------------------------- Prefix | users Verb | GET URI | /users(.:format) </span><span class="gp">Controller#</span>Action | <span class="nb">users</span><span class="c">#index</span> <span class="go">--[ Route 2 ]---------------------------------------------------- Prefix | Verb | POST URI | /users(.:format) </span><span class="gp">Controller#</span>Action | <span class="nb">users</span><span class="c">#create</span> <span class="go">--[ Route 3 ]---------------------------------------------------- Prefix | new_user Verb | GET URI | /users/new(.:format) </span><span class="gp">Controller#</span>Action | <span class="nb">users</span><span class="c">#new</span> <span class="go">--[ Route 4 ]---------------------------------------------------- Prefix | edit_user Verb | GET URI | /users/:id/edit(.:format) </span><span class="gp">Controller#</span>Action | <span class="nb">users</span><span class="c">#edit</span> </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails routes --expanded ">Copy</button> </div> <h3 id="searching-routes"><a class="anchorlink" href="#searching-routes" data-turbo="false"><span>5.2</span> Searching Routes</a></h3><p>You can search through your routes with the grep option: <code>-g</code>. This outputs any routes that partially match the URL helper method name, the HTTP verb, or the URL path.</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-g</span> new_comment <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-g</span> POST <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-g</span> admin </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails routes -g new_comment bin/rails routes -g POST bin/rails routes -g admin ">Copy</button> </div> <p>If you only want to see the routes that map to a specific controller, there's the controller option: <code>-c</code>.</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-c</span> <span class="nb">users</span> <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-c</span> admin/users <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-c</span> Comments <span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">-c</span> Articles::CommentsController </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails routes -c users bin/rails routes -c admin/users bin/rails routes -c Comments bin/rails routes -c Articles::CommentsController ">Copy</button> </div> <div class="interstitial info"><p>The output from <code>bin/rails routes</code> is easier to read if you widen your terminal window until the output lines don't wrap or use the <code>--expanded</code> option.</p></div><h3 id="listing-unused-routes"><a class="anchorlink" href="#listing-unused-routes" data-turbo="false"><span>5.3</span> Listing Unused Routes</a></h3><p>You can scan your application for unused routes with the <code>--unused</code> option. An "unused" route in Rails is a route that is defined in the config/routes.rb file but is not referenced by any controller action or view in your application. For example:</p><div class="interstitial code"> <pre><code class="highlight console"><span class="gp">$</span><span class="w"> </span><span class="nb">bin/rails </span>routes <span class="nt">--unused</span> <span class="go">Found 8 unused routes: </span><span class="gp"> Prefix Verb URI Pattern Controller#</span>Action <span class="gp"> people GET /people(.:format) people#</span>index <span class="gp"> POST /people(.:format) people#</span>create <span class="gp"> new_person GET /people/new(.:format) people#</span>new <span class="gp">edit_person GET /people/:id/edit(.:format) people#</span>edit <span class="gp"> person GET /people/:id(.:format) people#</span>show <span class="gp"> PATCH /people/:id(.:format) people#</span>update <span class="gp"> PUT /people/:id(.:format) people#</span>update <span class="gp"> DELETE /people/:id(.:format) people#</span>destroy </code></pre> <button class="clipboard-button" data-clipboard-text="bin/rails routes --unused ">Copy</button> </div> <h3 id="routes-in-rails-console"><a class="anchorlink" href="#routes-in-rails-console" data-turbo="false"><span>5.4</span> Routes in Rails Console</a></h3><p>You can access route helpers using <code>Rails.application.routes.url_helpers</code> within the <a href="command_line.html#bin-rails-console">Rails Console</a>. They are also available via the <a href="command_line.html#the-app-and-helper-objects">app</a> object. For example:</p><div class="interstitial code"> <pre><code class="highlight irb"><span class="gp">irb></span><span class="w"> </span><span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">url_helpers</span><span class="p">.</span><span class="nf">users_path</span> <span class="p">=></span> <span class="s2">"/users"</span> <span class="gp">irb></span><span class="w"> </span><span class="n">user</span> <span class="o">=</span> <span class="no">User</span><span class="p">.</span><span class="nf">first</span> <span class="p">=></span> <span class="kt">#<</span><span class="no">User</span><span class="p">:</span><span class="mh">0x00007fc1eab81628</span> <span class="gp">irb></span><span class="w"> </span><span class="n">app</span><span class="p">.</span><span class="nf">edit_user_path</span><span class="p">(</span><span class="n">user</span><span class="p">)</span> <span class="p">=></span> <span class="s2">"/users/1/edit"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="Rails.application.routes.url_helpers.users_path user = User.first app.edit_user_path(user) ">Copy</button> </div> <h2 id="testing-routes"><a class="anchorlink" href="#testing-routes" data-turbo="false"><span>6</span> Testing Routes</a></h2><p>Rails offers three built-in assertions designed to make testing routes simpler:</p> <ul> <li><a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates"><code>assert_generates</code></a></li> <li><a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes"><code>assert_recognizes</code></a></li> <li><a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_routing"><code>assert_routing</code></a></li> </ul> <h3 id="the-assert-generates-assertion"><a class="anchorlink" href="#the-assert-generates-assertion" data-turbo="false"><span>6.1</span> The <code>assert_generates</code> Assertion</a></h3><p><a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_generates"><code>assert_generates</code></a> asserts that a particular set of options generate a particular path and can be used with default routes or custom routes. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">assert_generates</span> <span class="s2">"/photos/1"</span><span class="p">,</span> <span class="p">{</span> <span class="ss">controller: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"show"</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"1"</span> <span class="p">}</span> <span class="n">assert_generates</span> <span class="s2">"/about"</span><span class="p">,</span> <span class="ss">controller: </span><span class="s2">"pages"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"about"</span> </code></pre> <button class="clipboard-button" data-clipboard-text="assert_generates "/photos/1", { controller: "photos", action: "show", id: "1" } assert_generates "/about", controller: "pages", action: "about" ">Copy</button> </div> <h3 id="the-assert-recognizes-assertion"><a class="anchorlink" href="#the-assert-recognizes-assertion" data-turbo="false"><span>6.2</span> The <code>assert_recognizes</code> Assertion</a></h3><p><a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_recognizes"><code>assert_recognizes</code></a> is the inverse of <code>assert_generates</code>. It asserts that a given path is recognized and routes it to a particular spot in your application. For example:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">assert_recognizes</span><span class="p">({</span> <span class="ss">controller: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"show"</span><span class="p">,</span> <span class="ss">id: </span><span class="s2">"1"</span> <span class="p">},</span> <span class="s2">"/photos/1"</span><span class="p">)</span> </code></pre> <button class="clipboard-button" data-clipboard-text="assert_recognizes({ controller: "photos", action: "show", id: "1" }, "/photos/1") ">Copy</button> </div> <p>You can supply a <code>:method</code> argument to specify the HTTP verb:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">assert_recognizes</span><span class="p">({</span> <span class="ss">controller: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"create"</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">path: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">method: :post</span> <span class="p">})</span> </code></pre> <button class="clipboard-button" data-clipboard-text="assert_recognizes({ controller: "photos", action: "create" }, { path: "photos", method: :post }) ">Copy</button> </div> <h3 id="the-assert-routing-assertion"><a class="anchorlink" href="#the-assert-routing-assertion" data-turbo="false"><span>6.3</span> The <code>assert_routing</code> Assertion</a></h3><p>The <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Assertions/RoutingAssertions.html#method-i-assert_routing"><code>assert_routing</code></a> assertion checks the route both ways. It combines the functionality of both <code>assert_generates</code> and <code>assert_recognizes</code>. It tests that the path generates the options, and that the options generate the path:</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="n">assert_routing</span><span class="p">({</span> <span class="ss">path: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">method: :post</span> <span class="p">},</span> <span class="p">{</span> <span class="ss">controller: </span><span class="s2">"photos"</span><span class="p">,</span> <span class="ss">action: </span><span class="s2">"create"</span> <span class="p">})</span> </code></pre> <button class="clipboard-button" data-clipboard-text="assert_routing({ path: "photos", method: :post }, { controller: "photos", action: "create" }) ">Copy</button> </div> <h2 id="breaking-up-a-large-route-file-with-draw"><a class="anchorlink" href="#breaking-up-a-large-route-file-with-draw" data-turbo="false"><span>7</span> Breaking Up a Large Route File With <code>draw</code></a></h2><p>In a large application with thousands of routes, a single <code>config/routes.rb</code> file can become cumbersome and hard to read. Rails offers a way to break up a single <code>routes.rb</code> file into multiple small ones using the <a href="https://api.rubyonrails.org/v8.0.0/classes/ActionDispatch/Routing/Mapper/Resources.html#method-i-draw"><code>draw</code></a> macro.</p><p>For example, you could add an <code>admin.rb</code> file that contains all the routes related to the admin area, another <code>api.rb</code> file for API related resources, etc.</p><div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/routes.rb</span> <span class="no">Rails</span><span class="p">.</span><span class="nf">application</span><span class="p">.</span><span class="nf">routes</span><span class="p">.</span><span class="nf">draw</span> <span class="k">do</span> <span class="n">get</span> <span class="s2">"foo"</span><span class="p">,</span> <span class="ss">to: </span><span class="s2">"foo#bar"</span> <span class="n">draw</span><span class="p">(</span><span class="ss">:admin</span><span class="p">)</span> <span class="c1"># Will load another route file located in `config/routes/admin.rb`</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text=" Rails.application.routes.draw do get "foo", to: "foo#bar" draw(:admin) # Will load another route file located in `config/routes/admin.rb` end ">Copy</button> </div> <div class="interstitial code"> <pre><code class="highlight ruby"><span class="c1"># config/routes/admin.rb</span> <span class="n">namespace</span> <span class="ss">:admin</span> <span class="k">do</span> <span class="n">resources</span> <span class="ss">:comments</span> <span class="k">end</span> </code></pre> <button class="clipboard-button" data-clipboard-text=" namespace :admin do resources :comments end ">Copy</button> </div> <p>Calling <code>draw(:admin)</code> inside the <code>Rails.application.routes.draw</code> block itself will try to load a route file that has the same name as the argument given (<code>admin.rb</code> in this example). The file needs to be located inside the <code>config/routes</code> directory or any sub-directory (i.e. <code>config/routes/admin.rb</code> or <code>config/routes/external/admin.rb</code>).</p><div class="interstitial note"><p>You can use the normal routing DSL inside a secondary routing file such as <code>admin.rb</code>, but <em>do not</em> surround it with the <code>Rails.application.routes.draw</code> block. That should be used in the main <code>config/routes.rb</code> file only.</p></div><div class="interstitial note"><p>Don't use this feature unless you really need it. Having multiple routing files make it harder to discover routes in one place. For most applications - even those with a few hundred routes - it's easier for developers to have a single routing file. The Rails routing DSL already offers a way to break routes in an organized manner with <code>namespace</code> and <code>scope</code>.</p></div> </section> <hr> <footer aria-labelledby="heading-feedback" role="region"> <h2 id="heading-feedback">Feedback</h2> <p> You're encouraged to help improve the quality of this guide. </p> <p> Please contribute if you see any typos or factual errors. To get started, you can read our <a href="https://edgeguides.rubyonrails.org/contributing_to_ruby_on_rails.html#contributing-to-the-rails-documentation">documentation contributions</a> section. </p> <p> You may also find incomplete content or stuff that is not up to date. Please do add any missing documentation for main. Make sure to check <a href="https://edgeguides.rubyonrails.org">Edge Guides</a> first to verify if the issues are already fixed or not on the main branch. Check the <a href="ruby_on_rails_guides_guidelines.html">Ruby on Rails Guides Guidelines</a> for style and conventions. </p> <p> If for whatever reason you spot something to fix but cannot patch it yourself, please <a href="https://github.com/rails/rails/issues">open an issue</a>. </p> <p>And last but not least, any kind of discussion regarding Ruby on Rails documentation is very welcome on the <a href="https://discuss.rubyonrails.org/c/rubyonrails-docs">official Ruby on Rails Forum</a>. </p> </footer> </div> </article> </main> <hr class="hide" /> <footer id="complementary"> <div class="wrapper"> <p>This work is licensed under a <a href="https://creativecommons.org/licenses/by-sa/4.0/">Creative Commons Attribution-ShareAlike 4.0 International</a> License</p> <p>"Rails", "Ruby on Rails", and the Rails logo are trademarks of David Heinemeier Hansson. All rights reserved.</p> </div> </footer> <a href="#main-skip-link" class="back-to-top" data-turbo="false"><span class="visibly-hidden">Back to top</span></a> </body> </html>