How to get file content from post rails - ruby-on-rails

I have a client in java that sends form post requests with video file.
I get in the server following POST:
Parameters: {"video"=>#<ActionDispatch::Http::UploadedFile:0x007f26783b49d0
#original_filename="video", #content_type=nil,
#headers="Content-Disposition: form-data; name=\"video\"; filename=\"video\"\r\n",
#tempfile=#<Tempfile:/tmp/RackMultipart20160405-3-106c9nr>>, "id"=>"36"}
I am trying to save the file to s3 using following lines:
I know the connection and actual saving works because I tried with base64 string as parameter and it worked well.
body = params[:video].tempfile
video_temp_file = write_to_file(body)
VideoUploader.new.upload_video_to_s3(video_temp_file, params[:id].to_s+'.mp4')
I see on s3 empty files or 24 bytes.
where do i do wrong?
Edit: I am using carrierwave:
def write_to_file(content)
thumbnail_file = Tempfile.new(['video','.mp4'])
thumbnail_file.binmode # note that the tempfile must be in binary mode
thumbnail_file.write content
thumbnail_file.rewind
thumbnail_file
end

Related

How can I to make upload of file maintain your original `Content Type` to Amazon S3?

TL;DR
How can I to upload an image and maintain its original Content Type or, generate a signed or public URL that force a correct type for my file?
I explain more:
I have a problem with S3 (I really I'm using Minio, that is compatible with S3 protocol) in Rails app with
gem 'aws-sdk-s3', '~> 1.96'
I create the follow method to handle uploaded file (in Rails App) and send it to Minio.
def upload_file(file)
object_key = "#{Time.now.to_i}-#{file.original_filename}"
object = #s3_bucket.object(object_key)
object.upload_file(Pathname.new(file.path))
object
end
This is my uploaded file with correct Content-Type, before it was sent to Minio.
# file
#<ActionDispatch::Http::UploadedFile:0x00007f47918ef708
#content_type="image/jpeg",
#headers=
"Content-Disposition: form-data; name=\"images[]\"; filename=\"image_test.jpg\"\r\nContent-Type: image/jpeg\r\n",
#original_filename="image_test.jpg",
#tempfile=#<File:/tmp/RackMultipart20220120-9-gc3x7n.jpg>>
And here, is my file, with incorrect Type ("binary/octet-stream") on Minio
I need to send it to another service, and get the upload URL with correct Content-Type.
So, how can I to upload an image and maintain its original Content Type or, generate a signed or public URL that force a correct type for my file?
You could use the put_object method on the bucket instance that accepts a hash of options, one of which is content-type (Reference):
def upload_file(file)
object_key = "#{Time.now.to_i}-#{file.original_filename}"
#s3_bucket.put_object({
key: object_key,
body: Pathname.new(file.path),
content_type: "some/content_type"
})
end

Reading blob audio data in Ruby

I need to send the raw audio data that a user records in the browser to an API.
I'm sending the raw blob object via POST to my Rails backend. It looks like this when recieved.
{"blob"=>#<ActionDispatch::Http::UploadedFile:0x00007f83ad01a7d8 #tempfile=#<Tempfile:/var/folders/cc/f7_d06hs6psbcxl87nwzsplr0000gn/T/RackMultipart20201021-933-1xu271c>, #original_filename="blob", #content_type="audio/wav", #headers="Content-Disposition: form-data; name=\"blob\"; filename=\"blob\"\r\nContent-Type: audio/wav\r\n">, "controller"=>"audios", "action"=>"interview"}
How can I read the actual data and extract it (without headers) to send to the external service?
The ActionDispatch::Http::UploadedFile looks similar to an IO object, so you can probably just:
uploaded_file = params["blob"]
raw_string = uploaded_file.read # do what you want with the raw data

Upload CSV via POST in Rails

I am trying to upload a csv file to Rails and parse it into a db. I have tried using both Paw and Postman to send the http request, specifying POST, attaching the csv file, and specifying Content-Type as application/csv
The request header:
POST /skate_parks/import HTTP/1.1
Content-Type: text/csv
Host: localhost:3000
Connection: close
User-Agent: Paw/2.3.4 (Macintosh; OS X/10.11.5) GCDHTTPRequest
Content-Length: 11663
Name,Address,Suburb,Postcode,State,Business Category,LGA,Region,
Aireys Inlet Skate Park,Great Ocean Road,Aireys Inlet,3231,VIC,Skate Parks,Surf Coast,Barwon S/W, etc...
The controller skate_parks_controller.rb
def import
SkatePark.import(params[:body])
end
The model
class SkatePark < ApplicationRecord
require 'csv'
def self.import(file)
CSV.foreach("file", headers: true) do |row|
skate_park_hash = row.to_hash
skate_park = SkatePark.where(name: skate_park_hash["name"])
if skate_park.count == 1
skate_park.first.update_attributes(skate_park_hash)
else
SkatePark.create!(skate_park_hash)
end
end
end
end
The error
Started POST "/skate_parks/import" for ::1 at 2016-05-26 13:48:34 +1000
Processing by SkateParksController#import as HTML
Completed 500 Internal Server Error in 3ms (ActiveRecord: 0.0ms)
Errno::ENOENT (No such file or directory # rb_sysopen - file):
app/models/skate_park.rb:6:in `import'
app/controllers/skate_parks_controller.rb:7:in `import'
The problem is params[:body] is nil, so you're essentially calling SkatePark.import(nil). Rails doesn't put the raw POST body into params like you've apparently assumed it does.
You have two options. The better option, in my opinion, is to upload the data as multipart/form-data. Rather than putting the raw data into the POST body, you'll do the same thing a browser does when a user chooses a file in an <input type="file">, which is to say you'll encode it as form data. When you do that, you will be able to access the data through params, as described in the Form Helpers Rails Guide under "Uploading Files." (Since you apparently aren't using a form, you can skip to "What Gets Uploaded" to see how to handle the data you receive.)
To test this with Postman, follow the instructions for "form-data" under "Request body" in the Sending Requests docs, which I'll excerpt here for posterity:
multipart/form-data is the default encoding a web form uses to transfer data. This simulates filling a form on a website, and submitting it. The form-data editor lets you set key/value pairs (using the key-value editor) for your data. You can attach files to a key as well.
Your other option is to access the POST body directly via request.raw_post as described here: How to access the raw unaltered http POST data in Rails? This is not very "Railsy," however, and among other things will be harder to test.

rails get request body 0byte

I get a request.body from web service
fp = File.open("/home/mm/mms/video_rest/video_mp.mp4", "wb")
fp.write(request.body.readline)
fp.close
but when file are create size a 0 bytes
how to view if request body are a file size or how to best way to get a video file from request body?
UPDATE
have a this params
{"video"=>#<ActionDispatch::Http::UploadedFile:0x007febdc497da0 #tempfile=#<Tempfile:/tmp/RackMultipart20151007-3197-14dis8n.mp4>, #original_filename="VID_20151006_153121393.mp4", #content_type="application/octet-stream", #headers="Content-Disposition: form-data; name=\"video_presentacion\"; filename=\"VID_20151006_153121393.mp4\"\r\nContent-Type: application/octet-stream\r\nContent-Transfer-Encoding: binary\r\n">}
how to create a file on folder and change Content-Type application/octet-stream for 'video/mp4'?
im try with:
fp = File.open("/home/mm/aa/video_rest/video_mp.mp4", "wb")
fp.write(params[:video])
fp.close
or direct for paperclipt
usuario.update_attributes!(:video => params[:video])
result => Content type invalid
Solved
on android http using a on params add a content type("video/mp4")
and work fine !
regards!

Uploading an image from an iphone app to a rails app with carrierwave

I'm trying to send an image from an iPhone app to a rails app through an internal api using carrier wave. I've put most of the code together from other questions on stack overflow and examples online - i've never done this type of thing before. I don't have the iPhone code as we're outsourcing it, but I can get it.
The code in my ApiController that receives the request looks like this:
def create_item
#item = upload_image(params[:img], params[:name], params[:content_type], params[:file_size])
end
private
def upload_image(img, name, content_type, file_size)
encoded_img = Base64.encode64(img)
io = FilelessIO.new(Base64.decode64(encoded_img))
io.original_filename = "#{name}"
item = Item.new
item.cover = io
item.content_type = content_type
item.file_size = file_size
item.save!(validate: false)
item
end
When they send the request the parameters look like the code below and it gives them a 500 error.
Parameters: {"img"=>#<ActionDispatch::Http::UploadedFile:0x007fc3b1f4f570 #original_filename="avatar.png", #content_type="image/png", #headers="Content-Disposition: form-data; name=\"img\"; filename=\"avatar.png\"\r\nContent-Type: image/png\r\n", #tempfile=#<Tempfile:/tmp/RackMultipart20130703-2-hfx7gg>>;, "controller"=>"api/v1/api", "action"=>"create_item", "uid"=>"100003052137695"}
The error I get is:
no implicit conversion of ActionDispatch::Http::UploadedFile into String
vendor/ruby-2.0.0/lib/ruby/2.0.0/base64.rb:38:in `pack'
The error you get indicates that iPhone is sending the actual file whereas you expect it to send a Base64 string from your code.
Check with your iPhone team and agree upon needed format:
They send Base64 string and you should get past this error
You change your code to accept the file (something like item.cover = params[:img])
HTH

Resources