Ruby and Puma – Read error: #

Was standing up a Puma web service late into the work day yesterday, and could not figure out why I was getting the below error when I should be seeing my results as a CSV result.

2013-05-28 19:00:59 -0500: Read error: #<NoMethodError: undefined method `each' for #<String:0x00000001611790>>
/home/reporting/reporting_mux/shared/bundle/ruby/1.9.1/gems/puma-2.0.1/lib/puma/server.rb:482:in `handle_request'
/home/reporting/reporting_mux/shared/bundle/ruby/1.9.1/gems/puma-2.0.1/lib/puma/server.rb:243:in `process_client'
/home/reporting/reporting_mux/shared/bundle/ruby/1.9.1/gems/puma-2.0.1/lib/puma/server.rb:142:in `block in run'
/home/reporting/reporting_mux/shared/bundle/ruby/1.9.1/gems/puma-2.0.1/lib/puma/thread_pool.rb:92:in `call'
/home/reporting/reporting_mux/shared/bundle/ruby/1.9.1/gems/puma-2.0.1/lib/puma/thread_pool.rb:92:in `block in spawn_thread'

The original return value of the call method was setup as:

[200, {"Content-Type" => "text/html"}, str]

For those with some more experience in using Puma, or Rack, you may even see what the problem was right away. Being my first attempt at standing up a Puma instance, I chased down a few red herrings, but at least they were needed updates. I first tried to update the MIME type to be text/comma-separated-values instead of text/html, and had the results setup to return as an attachment. These changes were kept, as they were the behavior of an existing implementation we are mirroring, but the call was still erroring out.

I finally stumbled across Puma’s Example config.rb file on Github.com and buried in there I saw the issue. The last element of the array returned by a Rack call method, has to be an Array, or at least Enumerable. I was returning a String, and that is what was causing the #<NoMethodError: undefined method `each' for #<String:0x00000001611790>>. I changed the last element to be the string wrapped in an array, and voilĂ , everything worked. So below is what I wound up with after the too long bug hunt.

[200, {"Content-Type" => "text/comma-separated-values",
       "Content-Disposition" => "attachment; filename=#{filename}" }, [str + "n"]]

Hope this helps someone else with a similar problem, and can save you the long evening of debugging that I went through.
–Proctor