How to download an image file via HTTP into a temp file?
Asked Answered
D

5

28

I've found good examples of NET::HTTP for downloading an image file, and I've found good examples of creating a temp file. But I don't see how I can use these libraries together. I.e., how would the creation of the temp file be worked into this code for downloading a binary file?

require 'net/http'

Net::HTTP.start("somedomain.net/") do |http|
    resp = http.get("/flv/sample/sample.flv")
    open("sample.flv", "wb") do |file|
        file.write(resp.body)
    end
end
puts "Done."
Deckard answered 27/8, 2013 at 20:7 Comment(4)
Did you submit the edit correctly? I suspect not otherwise your code seems like a direct copy of your first example.Conversazione
And what happens when you replace the open("sample.flv")... part with the stuff you read from the Tempfile docs?Mirisola
@Shadwell; this is the first example I've posted.Deckard
Okay, so maerics' question still stands then. What have you tried so far? (I assume more than just running the code from the first example and hoping it magically works!)Conversazione
U
50

There are more api-friendly libraries than Net::HTTP, for example httparty:

require "httparty"

url = "https://upload.wikimedia.org/wikipedia/commons/thumb/9/91/DahliaDahlstarSunsetPink.jpg/250px-DahliaDahlstarSunsetPink.jpg"

File.open("/tmp/my_file.jpg", "wb") do |f| 
  f.write HTTParty.get(url).body
end
Ubangishari answered 27/8, 2013 at 20:18 Comment(5)
Thanks; I was looking for an httparty example in binary mode like this.Deckard
Considering it's an image file, you might want to set f.binmode before starting to write to the file.Hydrophobia
@MariusButuc suggestion added.Ubangishari
add f.close as without it file may not get closed properly => 0B problemBluster
f.binmode is already covered by the file open mode wb. f.close is redundant because the File.open block will always close the file see https://mcmap.net/q/204174/-ruby-39-s-file-open-and-the-need-for-f-closeBioclimatology
M
17
require 'net/http'
require 'tempfile'
require 'uri'

def save_to_tempfile(url)
  uri = URI.parse(url)
  Net::HTTP.start(uri.host, uri.port) do |http|
    resp = http.get(uri.path)
    file = Tempfile.new('foo', Dir.tmpdir, 'wb+')
    file.binmode
    file.write(resp.body)
    file.flush
    file
  end
end

tf = save_to_tempfile('http://a.fsdn.com/sd/topics/transportation_64.png')
tf # => #<File:/var/folders/sj/2d7czhyn0ql5n3_2tqryq3f00000gn/T/foo20130827-58194-7a9j19> 
Mirisola answered 27/8, 2013 at 20:20 Comment(4)
Interesting. I get an encoding error running this with ruby 2.0 inside Rails: Encoding::UndefinedConversionError: "\x89" from ASCII-8BIT to UTF-8Deckard
@Deckard do then resp.body.force_encoding("ASCII-8BIT") and try the same.Schulte
The fix is adding "file.binmode".Deckard
Just a heads up, this won't work if the URL includes parameters, as eg. S3 authenticated urls.Tacky
M
10

I like to use RestClient:

file = File.open("/tmp/image.jpg", 'wb' ) do |output|
  output.write RestClient.get("http://image_url/file.jpg")
end
Memphis answered 18/7, 2014 at 14:50 Comment(0)
C
4

Though the answers above work totally fine, I thought I would mention that it is also possible to just use the good ol' curl command to download the file into a temporary location. This was the use case that I needed for myself. Here's a rough idea of the code:

# Set up the temp file:
file = Tempfile.new(['filename', '.jpeg'])

#Make the curl request:
url = "http://example.com/image.jpeg"
curlString = "curl --silent -X GET \"#{url}\" -o \"#{file.path}\""
curlRequest = `#{curlString}`
Chlordane answered 14/11, 2019 at 18:43 Comment(1)
For my case I was trying without the ['filename', '.jpeg'] array in the new tempfile and it wasn't working. Adding it made it work.Dissatisfactory
B
4

If you like to download a file using HTTParty you can use the following code.

resp = HTTParty.get("https://www.google.com/images/branding/googlelogo/2x/googlelogo_color_92x30dp.png")

file = Tempfile.new
file.binmode
file.write(resp.body)
file.rewind

Further, if you want to store the file in ActiveStorage refer below code.

object.images.attach(io: file, filename: "Test.png")
Beghard answered 19/1, 2021 at 10:5 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.