routing-filter is broken with Rails 7.1

Posted . Visible to the public.

If you are using the routing-filter Show snapshot gem in your Rails 7.1 app for managing URL segments for locales or suffixes, you will notice that the filters do no longer apply, routes are broken and the necessary parameters are no longer extracted. That is because routing-filter patches Rails' find_routes-method to get the current path and apply its defined filters on it. These filters then modify the params that are handed over to your controller action. This way you receive a locale parameter from a matching URL segment.

Before Rails 7.1, this method returned all associated routes (as enumerable) and the using methods iterated over them. As the using methods like serve do not actually need all routes, but may return early, a change Show snapshot has been introduced to add lazy behavior by adding an iterator block and yielding. This change breaks the adapter patch in routing-filter as it still expects an array of route data when calling super, but never actually calls the block that now needs to be called. Due to this, the return value is empty, no filters are applied and the routes go missing.

To fix this, you need to monkeypatch the patch/adapter in routing-filter until a new version may eventually come out. There is already an open PR Show snapshot .

In your app, create a file lib/ext/routing_filter/router_with_filtering.rb and add the following content:

if Gem.loaded_specs['routing-filter'].version >'0.7')
  raise 'Check if PR has been merged and released. If yes, delete this monkey patch.'

# We cannot prepend a custom extension module here because we call `super` in this method which should call the Rails
# #find_routes-method and not the routing_filter's #find_routes-method which is broken.
# Instead, we override the whole module definition to fix it.
module RoutingFilter
  module ActionDispatchJourneyRouterWithFiltering
    def find_routes(env)
      path = env.is_a?(Hash) ? env['PATH_INFO'] : env.path_info
      filter_parameters = {}
      original_path = path.dup, path, env) do

      super(env) do |match, parameters, route|
        parameters = parameters.merge(filter_parameters)

        if env.is_a?(Hash)
          env['PATH_INFO'] = original_path
          env.path_info = original_path

        yield [match, parameters, route]

  ActionDispatch::Journey::Router.send(:prepend, ActionDispatchJourneyRouterWithFiltering)

Add an initializer config/initializers/ext.rb, if not yet present:

Dir.glob(Rails.root.join('lib/ext/**/*.rb')).sort.each do |filename|
 require filename

Restart your application. The routing should now work again.

Dominic Beger
Last edit
Dominic Beger
Source code in this card is licensed under the MIT License.
Posted by Dominic Beger to makandra dev (2024-06-18 08:03)