Rails 7.1 adds new option path_params for url_for helper method

Neenu Chacko

Neenu Chacko

November 7, 2023

This blog is part of our  Rails 7 series.

With Rails 7.1, the url_for helper now supports a new option called path_params.

Prior to Rails 7.1, if you had your routes configured to be scoped under say, user_id as shown below, you would have to explicitly specify the user_id in every single place where you want to generate a link for the scoped routes, such as when writing view files.

#routes.rb
Rails.application.routes.draw do
  root "articles#index"

  scope ":user_id" do
    get "/articles", to: "articles#index"
    get "/articles/:id", to: "articles#show"
  end

  get "/categories", to: "categories#index"
end
<!-- app/views/articles/index.html.erb -->

<a href="<%= articles_path(user_id: @current_user.id) %>"> Articles </a>

This could be solved by updating ApplicationController and overwriting the default_url_options method:

# application_controller.rb
class ApplicationController < ActionController::Base
  def default_url_options
    { user_id: "unique-id" }
  end
end

The default_url_options method is used to overwrite and set default options for all the methods based on url_for. However, this meant that all routes, even those that did not belong to the user_id scope, would have the ?user_id=unique-id query param added to the end of them resulting in the following output:

articles_path # => /unique-id/articles
categories_path # => /categories?user_id=unique-id

Rails 7.1 fixes this issue with the addition of the path_params option. If you pass a hash of parameters to this key, those parameters will only be used for the named segments of the route. If they aren't used, they are discarded instead of being appended to the end of the route as query params.

With this change, we can implement the default_url_options method as follows:

class ApplicationController < ActionController::Base
  def default_url_options
    { path_params: { user_id: "unique-id" } }
  end
end

The url_for helper method will now give you the following output:

articles_path # => /unique-id/articles
articles_path(user_id: "test-id") # => /test-id/articles
categories_path # => /categories
categories_path(user_id: "test-id") # => /categories

The view file can now be written as:

<a href="<%= articles_path %>"> Articles </a>

This is very useful in situations where you only want to add a required param that is part of the route's URL without introducing unnecessary query params for other routes.

Please check out this pull request for more details.

If this blog was helpful, check out our full blog archive.

Stay up to date with our blogs.

Subscribe to receive email notifications for new blog posts.