Below is one of my API code in my new Rails application
module Api module V1 class VendorOnboardingController < Api::BaseController include Concerns::Api::V1::VendorOnboardingApipie def enrollment result = Parse::Vendor.new(Hash.from_xml(request.body).deep_symbolize_keys!) ...remaining code---- end end end end
The API working fine locally and on server running thin as application server.After testing we moved the code to UAT server running on Passenger as application server and the API boomed with below error:
“undefined method `eof?’ for PhusionPassenger::Utils::TeeInput:0x000056122fc69a20”
After breaking a lot of head and changing code with hit and trial method realized the culprit code is request.body in below line of code.
result = Parse::Vendor.new(Hash.from_xml(request.body).deep_symbolize_keys!)
changing it to request.body.read as below fixed the issue.
result = Parse::Vendor.new(Hash.from_xml(request.body.read).deep_symbolize_keys!)
Understanding the Problem:
Rails communicate with application server through Rack.
Infact Rack sits between all the frameworks (Rails, Sinatra, Rulers) and all the app servers (thin, unicorn, Rainbows, mongrel) as an adapter. Now if you see rack spec it says
The input stream is an IO-like object which contains the raw HTTP POST data. When applicable, its external encoding must be “ASCII-8BIT” and it must be opened in binary mode, for Ruby 1.9 compatibility. The input stream must respond to gets, each, read and rewind.
So in my local or with thin the request body was always coming as a StringIO object, so not causing any problem when the subsequent line of my code operating on it, but with passenger some how, this is not the case so code is breaking.
calling request.body.read will explicitly convert the request body to StringIO object and so fixed the problem.