rubyonrails rails guide guias basics ruby rack middleware

ruby - rails - ¿Cómo uso un middleware de Rack solo para ciertas rutas?



ruby rack web server (2)

Me gustaría que MyMiddleware ejecute en mi aplicación Rack, pero solo para ciertas rutas. Esperaba usar Rack::Builder o, al menos, Rack::URLMap , pero no sé cómo.

Esto es lo que pensé que funcionaría, pero no lo hace:

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

O, mejor aún, con un Regexp:

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

Pero el map parece exigir una aplicación al final; no retrocederá simplemente pasando el control a su padre. (El error real es el " undefined method ''each'' for nil:NilClass " cuando Rack intenta convertir el final de ese bloque do...end en una app ).

¿Hay un middleware por ahí que toma una serie de middlewares y una ruta y solo los ejecuta si la ruta coincide?


Esto no funciona porque @app no existe en el ámbito correcto:

# in my_app.ru or any Rack::Builder context: @app = self map ''/foo'' do use MyMiddleware run lambda { |env| @app.call(env) } end

Pero esto va a:

# in my_app.ru or any Rack::Builder context: ::MAIN_RACK_APP = self map ''/foo'' do use MyMiddleware run lambda { |env| ::MAIN_RACK_APP.call(env) } end

Rack::Builder elimina el primer argumento para map el frente de la ruta, por lo que no repite sin cesar. Desafortunadamente, esto significa que después de eliminar el prefijo de la ruta, es poco probable que el resto de la ruta coincida con otras asignaciones.

Aquí hay un ejemplo:

::MAIN_APP = self use Rack::ShowExceptions use Rack::Lint use Rack::Reloader, 0 use Rack::ContentLength map ''/html'' do use MyContentTypeSettingMiddleware, ''text/html'' run lambda { |env| puts ''HTML!''; ::MAIN_APP.call(env) } end map ''/xml'' do use MyContentTypeSettingMiddleware, ''application/xml'' run lambda { |env| puts ''XML!''; ::MAIN_APP.call(env) } end map ''/'' do use ContentType, ''text/plain'' run lambda { |env| [ 200, {}, "<p>Hello!</p>" ] } end

Ir a /html/xml hace que lo siguiente vaya al registro:

HTML! XML! 127.0.0.1 - - [28/May/2009 17:41:42] "GET /html/xml HTTP/1.1" 200 13 0.3626

Es decir, la aplicación asignada a ''/html'' tiras ''/html'' prefijo ''/html'' y la llamada ahora coincide con la aplicación asignada a ''/xml'' .


Podría hacer que MyMiddleware compruebe la ruta y no pase el control a la siguiente pieza de middleware si coincide.

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

O bien, puede utilizar URLMap sin el dslness. Se vería algo como esto:

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

URLMap es bastante simple de asimilar .