Question: Content of variable changing after read in ruby

Question

Content of variable changing after read in ruby

Answers 1
Added at 2016-12-28 01:12
Tags
Question

I am new to ruby (started yesterday) and I'm playing a bit with sinatra to build an API. I encountered an issue which left me without clue:

post '/login' do
    if request.body.read.length == 0
       halt 400 # bad request 
    else
        body = JSON.parse(request.body.read)
    end
end

When I executed this code, I had an error because I tried to parse an empty string with body = JSON.parse(request.body.read). In fact, I had to save request.body.read in another variable to use it twice (or more), because it's like request.body gets "consumed" after the first use.

This reminds me of borrows with rust, but here I wasn't expecting that and can't express it on google to find any documentation. Can anyone explain me what happened and why request.body is readable only one time?

For people who have the same problem (we never know), here's the fix:

post '/login' do
    body = request.body.read

    if body.length == 0
        halt 400 # bad request
    else
        body_json = JSON.parse(body)
    end
end

I heard about IO objects but I still can't go further in my researches.

Answers to

Content of variable changing after read in ruby

nr: #1 dodano: 2016-12-28 02:12

request.body is an input stream.

Streams are a basic data structure in computing where data is provided in sequence and has to be consumed in sequence. For example data sent over the internet is a stream.

Stream processing is very powerful because it allows you process data that is bigger than a machine's memory, for example movies on Netflix are streamed to your computer so they never have to store the entire movie but the current frames only.

Typically streams can only be read once. If you want to access the stream data more than once you have to buffer it. Which is what you're doing with body = request.body.read, well done!

Some streams are rewindable. As it happens the request.body in Sinatra is rewindable, so you can rewind it to the begin and read it all again.

request.body.read
request.body.rewind
request.body.read # => returns the content again
Source Show
◀ Wstecz