Reputation: 2667
I'm learning Ruby + Sinatra, and found a good post here which talks about how to upload files.
post '/upload/:filename' do
userdir = "./upload"
FileUtils.mkdir_p(userdir) unless File.exists?(userdir)
filename = File.join(userdir, params[:filename])
datafile = params[:data]
File.open(filename, 'wb') do |file|
file.write(datafile[:tempfile].read)
end
end
I can use the following cURL command to upload files fine.
curl -v -F "data=@/Users/me/Desktop/test.pdf" http://localhost:4567/upload/test.pdf
But now I had decided to use JSON to handle all incoming/outgoing responses. I tried this, but it didn't seem to work.
curl -i -X POST -H Accept:application/json -H Content-Type:application/json -d '{file:{filename:"test.pdf",md5sum:"ab3d2f"}}' --data-binary @/Users/me/Desktop/test.pdf 'http://localhost:4567/upload/test.pdf'
I also received an error like this:
NoMethodError at /upload/test.pdf
undefined method `get' for #<WebTest:0x101374dd8>
file: web.rb location: POST /upload/:filename line: 48
What should I do now?
Edited:
Line 48 is this file.write(datafile[:tempfile].read
Please help!
Upvotes: 1
Views: 1545
Reputation: 2667
Now I can get it working with the below curl command with JSON:
curl -v -F 'json=[ {"filename": "@/Users/me/Desktop/test.pdf", "md5sum": "1496f9b6f42b7ed8260eadeb158c33f4", type": "generic"}, {"filename": "@/Users/me/Desktop/test2.pdf", "md5sum": "1496f9b6f42b7ed8260eadeb158c33f4", type": "generic"} ]' http://localhost:4567/upload
However, since I don't use -F 'file=@/Users/me/Desktop/test.pdf'
to POST my file, how do I retrieve the file on the server-side using JSON objects?
The below is no longer working.
tempfile = params[:file][:tempfile]
filename = params[:file][:filename]
dest = "#{userdir}/#{filename}"
FileUtils.cp(tempfile.path, dest) if not File.exists?(dest)
Upvotes: 0
Reputation: 4653
I'm not sure what you're expecting your second curl command to do, but I'm pretty sure it's not doing what you want. If you give more than one --data
or -d
parameters to curl, their values will be joined together, separated by &
.
For example, if you have a file test.txt
with contents This is a test.
and you do request like this:
curl -i -X POST -H Accept:application/json -H Content-Type:application/json \
-d '{file:{filename:"test.txt",md5sum:"ab3d2f"}}' \
--data-binary @test.txt 'http://localhost:4567/upload/test.txt'
This is what the request looks like:
POST /upload/test.txt HTTP/1.1
User-Agent: curl/7.24.0 (x86_64-apple-darwin12.0) libcurl/7.24.0 OpenSSL/0.9.8r zlib/1.2.5
Host: localhost:4567
Accept:application/json
Content-Type:application/json
Content-Length: 61
{file:{filename:"test.txt",md5sum:"ab3d2f"}}&This is a test.
The request body is not valid JSON. It's not valid URL-encoded form data or multi-part form data either.
It's not obvious how to combine JSON requests with file uploads. Here are some options:
multipart/form-data
. That is, do what you're doing right now with your Ruby code and -F
option to curl. multipart/form-data
with one part of JSON for metadata and other part with the raw uploaded file.I'd probably go with the first option, because it's so widely supported.
Upvotes: 2
Reputation: 27553
Seems like your Ruby code is broken; you forgot an end
:
post '/upload/:filename' do
userdir = "./upload"
FileUtils.mkdir_p(userdir) unless File.exists?(userdir)
filename = File.join(userdir, params[:filename])
datafile = params[:data]
File.open(filename, 'wb') do |file|
file.write(datafile[:tempfile].read)
end
end
Upvotes: 1