Rails 7.1 Adds path_params Option For url_for Helper Method

In Rails, the url_for helper method is used to generate URLs with given set of parameters for different actions within our application.

# Generating a URL for a specific controller action

url_for(controller: 'posts', action: 'show', id: 1)

# Output: "/posts/1"
# Generating a URL with named routes

url_for(controller: 'posts', action: 'index')

# Output: "/posts"
# Generating a URL with additional parameters

url_for(controller: 'posts', action: 'index', page: 2)

# Output: "/posts?page=2"
# routes.rb
Rails.application.routes.draw do
  get 'posts/:id', to: 'posts#show', as: 'post'
end
# Generating a URL using a named route

url_for(post_path(1))

# Output: "/posts/1"
# Generating a URL for a specific object

post = Post.find(1)
url_for(post)

# Output: "/posts/1"

Before

Before Rails 7.1, when routes were scoped (e.g., under user_id), generating links for scoped routes in view files require explicit specification of user_id in every instance, creating repetitive code for link generation.

Rails.application.routes.draw do
  scope "user_id" do
    get "/posts", to: "posts#index", as: :posts
    get "/posts/:id", to: "posts#show", as: :post
  end

  get "/comments", to: "comments#index", as: :comments

  delete "/signout", to: "sessions#destroy", as: :signout
end
<!-- app/views/posts/index.html.erb -->

<a href="<%= posts_path(user_id: current_user.id) %>"> Post </a>

Instead of passing user_id to every scoped URL, we can set a default value for user_id using default_url_options method inside ApplicationController.

default_url_options method allows us to set default URL options that will be used by URL-generating methods, such as url_for, across the entire application.

class ApplicationController < ActionController::Base
  def default_url_options
    { user_id: current_user.id }
  end
end

However, with the default_url_options configuration, all routes, those lived outside the user_id scope (like authentication routes or comment routes) will have ?user_id=current_user.id query parameter at their end.

posts_path # => /current_user.id/posts

comments_path # => /comments?user_id=current_user.id

signout_path # => /signout?user_id=current_user.id

After

The above behavior causes URLs for non-scoped routes to include the scoped parameters set by default_url_options, leading to potential confusion, incorrect URLs, and aesthetics issues in scenarios where the parameters are not expected or needed.

The introduction of path_params option in Rails 7.1 for url_for method addresses the above issue by allowing specified parameters to be used exclusively for named segments of the route, avoiding their addition to non-segment parts of URLs.

class ApplicationController < ActionController::Base
  def default_url_options
    { path_params: { user_id: current_user.id } }
  end
end

url_for helpers will now behave as follows:

posts_path # => /current_user.id/posts
posts_path(user_id: 2) # => /2/posts

comments_path # => /comments
comments_path(user_id: 2) # => /comments?user_id=2

signout_path # => /signout
signout_path(user_id: 2) # => /signout?user_id=2

Lets discuss the above example in detailed manner:

  • posts_path generates the path /current_user.id/posts, using the default user_id provided by path_params.

  • posts_path(user_id: 2) generates the path /2/posts, explicitly specifying user_id as 2. It overrides the default user_id provided by path_params.

  • comments_path generates the path /comments without any additional parameters.

  • comments_path(user_id: 2) generates the path /comments?user_id=2, adding user_id as a query parameter since comments_path doesn’t have a named segment for user_id.

  • signout_path generates the path /signout without any additional parameters.

  • signout_path(user_id: 2) generates the path /signout?user_id=2, adding user_id as a query parameter, similar to comments_path.

Summary

Scoping routes under any value (e.g. user_id) leads to redundancy, requiring explicit value (user_id) inclusion in URL helper methods.

As default_url_options affecting non-scoped routes like authentication ones by adding the scoped value (user_id) as query params resulting in unexpected outputs.

Where as path_params enables specified parameters to be exclusively used for named segments in scoped routing, preventing unnecessary additions to every URL.

Need expert help with Rails?

Saeloun is a Rails Foundation Contributing Member helping teams modernize, upgrade, scale, and maintain production Rails applications.

Our Expertise

  • Rails contributors
  • 500+ Technical Articles
  • Production Rails consulting
  • Performance Optimization

Services

  • Rails application development
  • Code Audits
  • Rails upgrades
  • Team Augmentation

Need help on your Ruby on Rails or React project?

Join Our Newsletter