-->

Hello World rack middleware with rails 3: how to p

2020-06-18 03:45发布

问题:

i want to try out a simple rack middleware "hello world", but i seem to get stuck. it looks like the main sytax changed, since some examples use this code:

require 'rack/utils'

class FooBar

  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, body = @app.call(env)
         body.body << "\nHi from #{self.class}"
         [status, headers, body]
  end
end

produces an error:

undefined method `<<' for #<ActionDispatch::Response:0x103f07c48>

even when i look at other codes out there, i cannot seem to get them running with rails 3.0.3.

here are my concrete questions:

  • how can i get a simple rack middleware to run and modify the body of any output from a rails app?
  • where should i put the Rails.application.config.middleware.use declaration? (i created an own initializer in config/initializers for that)

thanks a lot in advance!

回答1:

This should do what you want it to:

# in config/application.rb
config.middleware.use 'FooBar'

# in config/initializers/foo_bar.rb
class FooBar
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    [status, headers, response.body << "\nHi from #{self.class}"]
  end
end

Be advised, that on just about every other request (at least on Rails 3.0.3), this will fail due to another middleware (Rack::Head) because it sends an empty request when content is unchanged. We are in this example depending on being able to call response.body, but in fact, the last member of the array can be anything that responds to .each.

Ryan Bates goes over Rack pretty well here:

http://asciicasts.com/episodes/151-rack-middleware

http://railscasts.com/episodes/151-rack-middleware

And the official Rails guide is pretty good too:

http://guides.rubyonrails.org/rails_on_rack.html

And of course the official Rack spec:

http://rack.rubyforge.org/doc/SPEC.html



回答2:

Rails 3.2.12+:

previous answer does not work for Rails 3.2.12+

This one does:

# in config/application.rb
config.middleware.use 'FooBar'

# in config/initializers/foo_bar.rb
class FooBar
  def initialize(app)
    @app = app
  end

  def call(env)
    status, headers, response = @app.call(env)
    response.body += "\nHi from #{self.class}"
    # response.body << "..." WILL NOT WORK
    [status, headers, response]
  end
end