21

I'm going through the tekpub rack tutorial but when I try to run even a basic program in rack i get this error.

ERROR Rack::Lint::LintError: Response body must respond to each
/Users/adam/.rvm/gems/ruby-1.9.3-preview1/gems/rack-1.3.4/lib/rack/lint.rb:19:in     `assert'
/Users/adam/.rvm/gems/ruby-1.9.3-preview1/gems/rack-1.3.4/lib/rack/lint.rb:513:in `each'
/Users/adam/.rvm/gems/ruby-1.9.3-preview1/gems/rack-1.3.4/lib/rack/body_proxy.rb:23:in `method_missing'
/Users/adam/.rvm/gems/ruby-1.9.3-preview1/gems/rack-1.3.4/lib/rack/chunked.rb:23:in `each'
/Users/adam/.rvm/gems/ruby-1.9.3-preview1/gems/rack-1.3.4/lib/rack/handler/webrick.rb:71:in `service'
/Users/adam/.rvm/rubies/ruby-1.9.3-preview1/lib/ruby/1.9.1/webrick/httpserver.rb:138:in `service'
/Users/adam/.rvm/rubies/ruby-1.9.3-preview1/lib/ruby/1.9.1/webrick/httpserver.rb:94:in `run'
/Users/adam/.rvm/rubies/ruby-1.9.3-preview1/lib/ruby/1.9.1/webrick/server.rb:191:in `block in start_thread'

This is the program im trying to run:

class EnvironmentOutput

  def call(env)
     ["200",{"Content-Type" => "text/plain"}, "Hello World"]
  end

end

run EnvironmentOutput.new

I'm a beginner programmer so I'm not sure whats going on. Tried google searches but nothing has come up.

Using ruby 1.9.3 Rack 1.1

Thanks

AFraser
  • 996
  • 4
  • 13
  • 27

4 Answers4

41

This is a change in Ruby 1.9.2 and, as has been suggested, if you surround your string with ["brackets"] it will turn "Hello World" into an array with a single value. Sounds silly, but that's the deal :).

It used to be that a String in Ruby would respond to each with an iteration of characters. Evidently there have been changes that way.

  • 1
    Thanks Rob, you'd get my vote up but I need more reputation :) – AFraser Oct 18 '11 at 08:33
  • 5
    the solution is correct but the real explanation is that rack tries to iterate on the array and tries to send into the HTTP connection the response reading all the element in the array and sending it in chunks. Very useful if you think you can create a block to control the streaming of the response body. – makevoid Feb 17 '12 at 20:36
  • ["200",{"Content-Type" => "text/plain"}, ["Hello World"]] works for me – vajapravin Apr 02 '14 at 15:03
8

Perhaps you can try this.

require 'stringio'

class EnvironmentOutput
  def call(env)
   ["200",{"Content-Type" => "text/plain"}, StringIO.new("Hello World")]
  end
end

run EnvironmentOutput.new

According to the rack spec, the body must only yield strings, but must not be a string itself. It specifically states failing to do so will not work in 1.9. What I've done here is wrap the string body in a StringIO instance. StringIO acts like a file handle and returns string output.

matt
  • 78,533
  • 8
  • 163
  • 197
Blake Taylor
  • 9,217
  • 5
  • 38
  • 41
1

since the error is ERROR Rack::Lint::LintError: Response body must respond to each. you get that the "Hello World" being a simple string, doesn't support each. Simple answer to that is just to add the [] to the string, turning it into an array and therefore supporting each.

class EnvironmentOutput
  def call(env)
    ["200",{"Content-Type" => "text/plain"}, ["Hello World"]]
  end
end

run EnvironmentOutput.new
0

This answer seems to answer your question:

If you check out the rack spec (found here: http://rack.rubyforge.org/doc/SPEC.html) under the body section it says:

The Body must respond to each and must only yield String values. The Body itself should not be an instance of String, as this will break in Ruby 1.9.

Community
  • 1
  • 1
ryantm
  • 8,217
  • 6
  • 45
  • 57