Reordering middleware is very complicated

Due to the way middleware stack is constructed in a deferred manner reordering middleware is terribly complicated.

Prior to 6.0.3 you could get away with stuff like:

  session_operations = Rails::Configuration::MiddlewareStackProxy.new([
     [:delete, RailsMultisite::Middleware],
     [:unshift, [RailsMultisite::Middleware, RailsMultisite::DiscoursePatches.config]],
  ])

  Rails.configuration.middleware = Rails.configuration.middleware + session_operations

However this terrible hack no longer works due to Ruby 2.7 fixes, that just store procs in the operation list.

https://github.com/rails/rails/issues/26303

Talks about this issue.

@rafaelfranca started a refactor here, which is still not merged:

https://github.com/rails/rails/pull/27936

The ideal result should be that we can do:

 Rails.configuration.middleware.delete RailsMultisite::Middleware
 Rails.configuration.middleware.unshift RailsMultisite::Middleware, RailsMultisite::DiscoursePatches.config

It is a sensible API and it is just super surprising that the result of those two operations is that there is no RailsMultisite::Middleware in the stack.

We added some apis to move middleware, but that is not enough, in some cases you want to remove / insert the same middleware with a different config.

5 Likes

I have to agree that even after over a decade working with Rails, configuring the middleware stack is still a painful process.

I think it’s over complicated because you start from an existing stack, and then insert / delete / reorder items dynamically inside it.

Sometimes I wonder if a simple, explicit list like Django does wouldn’t be better. But I understand how that would make it harder to upgrade, and hader for engines/plugins to insert their middlewares.

3 Likes