routing-filter is broken with Rails 7.1

Posted . Visible to the public.

If you are using the routing-filter Show archive.org 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 archive.org 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 archive.org 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 > Gem::Version.new('0.7')
  raise 'Check if PR https://github.com/svenfuchs/routing-filter/pull/87 has been merged and released. If yes, delete this monkey patch.'
end

# 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

      @routes.filters.run(:around_recognize, path, env) do
        filter_parameters
      end

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

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

        yield [match, parameters, route]
      end
    end
  end

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

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
end

Restart your application. The routing should now work again.

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