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.
1#routes.rb 2Rails.application.routes.draw do 3 root "articles#index" 4 5 scope ":user_id" do 6 get "/articles", to: "articles#index" 7 get "/articles/:id", to: "articles#show" 8 end 9 10 get "/categories", to: "categories#index" 11end
1<!-- app/views/articles/index.html.erb --> 2 3<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:
1# application_controller.rb 2class ApplicationController < ActionController::Base 3 def default_url_options 4 { user_id: "unique-id" } 5 end 6end
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:
1articles_path # => /unique-id/articles 2categories_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:
1class ApplicationController < ActionController::Base 2 def default_url_options 3 { path_params: { user_id: "unique-id" } } 4 end 5end
The url_for helper method will now give you the following output:
1articles_path # => /unique-id/articles 2articles_path(user_id: "test-id") # => /test-id/articles 3categories_path # => /categories 4categories_path(user_id: "test-id") # => /categories
The view file can now be written as:
1<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.