PullTempfile
Simple way how to download file from url to temporary file. (Please read more on "why" would you need to do this down bellow)
Gem has no runtime gem dependancies (just standard Ruby lib) and it's really lightweight.
Installation
Add this line to your application's Gemfile:
gem 'pull_tempfile'
And then execute:
$ bundle
Or install it yourself as:
$ gem install pull_tempfile
Usage
Simplest example
require 'pull_tempfile'
original_filename = 'no idea.png'
url = 'https://meme.eq8.eu/noidea.jpg'
file = PullTempfile.pull_tempfile(url: url, original_filename: original_filename)
file.unlink # delete file after you done
# ...or
PullTempfile.transaction(url: url, original_filename: original_filename) do |tmp_file|
puts tmp_file.path
# ...
end
transaction
will automatically delete (unlink
) the temporary file after block
finish.
Paperclip & Rails
require 'pull_tempfile'
class Medium < ActiveRecord::Base
has_attached_file :file
# ...
end
# when used as "AWS S3 browser upload" you can fetch original filename as "${filename}" metadata
# or use some different way to determine the file name.
original_filename = 'no idea.png'
url = 'https://meme.eq8.eu/noidea.jpg'
medium = Media.new
PullTempfile.transaction(url: url, original_filename: original_filename) do |tmp_file|
medium.file = tmp_file
medium.save!
end
Use HTTParty
PullTempfile.config.puller = ->(url){ HTTParty.get(url) }
License
The gem is available as open source under the terms of the MIT License.
Reason why this Gem exist:
This gem is trying to be usecase agnostic. For example you can use it to download CSV report and parse it and the CSV will automatically be deleted:
PullTempfile.transaction(url: 'https://mycompany.org/stupid-csv-report.csv', original_filename: 'dont-care.csv') do |tmp_file|
CSV.foreach(tmp_file.path) do |row|
# ....
end
end
But main reason for it's existence is that when you using gem paperclip > 3.1.4
you can do something like this to pull file from url:
class User < ActiveRecord::Base
attr_reader :avatar_remote_url
has_attached_file :avatar
def avatar_remote_url=(url_value)
self.avatar = URI.parse(url_value)
# Assuming url_value is http://example.com/photos/face.png
# avatar_file_name == "face.png"
# avatar_content_type == "image/png"
@avatar_remote_url = url_value
end
end
user = User.new
user.avatar_remote_url = 'http://example.com/photos/face.png'
user.save!
And this is how you upload file from url.
source https://github.com/thoughtbot/paperclip/wiki/Attachment-downloaded-from-a-URL
The problem is that if you do this on AWS S3 signd url is sending binary mime type
binary/octet-stream
and therefore
if you are implementing validations on your uploads:
class User < ActiveRecord::Base
# ...
validates_attachment_content_type :avatar, :content_type => ["image/jpg", "image/jpeg", "image/png", "image/gif"]
# ...
end
...you'll get error:
Validation failed: File has contents that are not what they are
reported to be, File is invalid, File content type is invalid
One solution is to skip validations in this context:
#...
medium.save!(validate: false) # will skip validations
...but that's not secure.
Yes you can use context validations, or implement validations differently http://www.eq8.eu/blogs/22-different-ways-how-to-do-rails-validations but that's not the point,
So way how to get around this is to download the file to your /tmp/
folder as a temp
file, and upload it via Paperclip
Install gem httparty
# Gemfile
# ...
gem 'httparty'
# ...
Run bundle install
Next create new file ./lib/s3_helper.rb
require 'httparty' # gem
module S3Helper
def pull_asset(url:, destination:)
File.open(destination, "wb") do |f|
f.binmode
f.write HTTParty.get(url).parsed_response
f.close
end
end
end
And now you can do something like:
user = User.new
require Rails.root.join('lib', 's3_helper')
S3Helper.pull_asset(url: "http://s3....../bbuesubeueueue", destination: "/tmp/my-file.jpg")
user.avatar = File.open("/tmp/my-file.jpg")
user.save!
But the problem is that you need to delete this file manually. So why
not to take advantage of Ruby Tempfile
. This is exactly what this gem
is doing. Have a look on the Source code https://github.com/equivalent/pull_tempfile/blob/master/lib/pull_tempfile.rb