Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I use a Rack middleware only for certain paths?

I'd like to have MyMiddleware run in my Rack app, but only for certain paths. I was hoping to use Rack::Builder or at least Rack::URLMap, but I can't quite figure out how.

This is what I thought would work, but doesn't:

# in my rackup file or Rails environment.rb:
map '/foo' do
  use MyMiddleware, { :some => 'options' }
end

Or, better yet, with a Regexp:

map /^foo/ do
  use MyMiddleware, { :some => 'options' }
end

But map seems to demand an app at the end; it won't fall back on just passing control back to its parent. (The actual error is "undefined method 'each' for nil:NilClass" from when Rack tries to turn the end of that do...end block into an app.)

Is there a middleware out there that takes an array of middlewares and a path and only runs them if the path matches?

like image 750
James A. Rosen Avatar asked May 28 '09 13:05

James A. Rosen


People also ask

How does Rack middleware works?

Rack middleware is a way to filter a request and response coming into your application. A middleware component sits between the client and the server, processing inbound requests and outbound responses, but it's more than interface that can be used to talk to web server.

Is rails a Rack app?

2.1 Rails Application's Rack Objectapplication is the primary Rack application object of a Rails application. Any Rack compliant web server should be using Rails.

What is Rack application?

Rack is a modular interface between web servers and web applications developed in the Ruby programming language. With Rack, application programming interfaces (APIs) for web frameworks and middleware are wrapped into a single method call handling HTTP requests and responses.


1 Answers

You could have MyMiddleware check the path and not pass control to the next piece of middle ware if it matches.

class MyMiddleware
  def initialize app
    @app = app
  end
  def call env
    middlewary_stuff if env['PATH_INFO'] == '/foo'
    @app.call env
  end

  def middlewary_stuff
    #...
  end
end

Or, you could use URLMap w/o the dslness. It would look something like this:

main_app = MainApp.new
Rack::URLMap.new '/'=>main_app, /^(foo|bar)/ => MyMiddleWare.new(main_app)

URLMap is actually pretty simple to grok.

like image 85
BaroqueBobcat Avatar answered Nov 15 '22 15:11

BaroqueBobcat