Ruby on Rails Constraints


You can filter what routes are available using constraints.

There are several ways to use constraints including:

For example, a requested based constraint to only allow a specific IP address to access a route:

constraints(ip: /127\.0\.0\.1$/) do
  get 'route', to: "controller#action"

See other similar examples ActionDispatch::Routing::Mapper::Scoping.

If you want to do something more complex you can use more advanced constraints and create a class to wrap the logic:

# lib/api_version_constraint.rb
class ApiVersionConstraint
  def initialize(version:, default:)
    @version = version
    @default = default

  def version_header

  def matches?(request)
    @default || request.headers["Accept"].include?(version_header)

# config/routes.rb
require "api_version_constraint"

Rails.application.routes.draw do
  namespace :v1, constraints: 1, default: true) do
    resources :users # Will route to app/controllers/v1/users_controller.rb

  namespace :v2, constraints: 2) do
    resources :users # Will route to app/controllers/v2/users_controller.rb

One form, several submit buttons

You can also use the value of the submit tags of a form as a constraint to route to a different action. If you have a form with multiple submit buttons (eg "preview" and "submit"), you could capture this constraint directly in your routes.rb, instead of writing javascript to change the form destination URL. For example with the commit_param_routing gem you can take advantage of rails submit_tag

Rails submit_tag first parameter lets you change the value of your form commit parameter

# app/views/orders/mass_order.html.erb
<%= form_for(@orders, url: mass_create_order_path do |f| %>
    <!-- Big form here -->
  <%= submit_tag "Preview" %>
  <%= submit_tag "Submit" %>
  # => <input name="commit" type="submit" value="Preview" />
  # => <input name="commit" type="submit" value="Submit" />
<% end %>

# config/routes.rb
resources :orders do
  # Both routes below describe the same POST URL, but route to different actions 
  post 'mass_order', on: :collection, as: 'mass_order',
    constraints:'Submit'), action: 'mass_create' # when the user presses "submit"
  post 'mass_order', on: :collection,
    constraints:'Preview'), action: 'mass_create_preview' # when the user presses "preview"
  # Note the `as:` is defined only once, since the path helper is mass_create_order_path for the form url
  # CommitParamRouting is just a class like ApiVersionContraint