PullTempfile
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
class Medium < ActiveRecord::Base
has_attached_file :file
# ...
end
require 'pull_tempfile'
# 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 = 'my face.jpg'
medium = Media.new
PullTempfile.transaction(url: url, original_filename: original_filename) do |tmp_file|
medium.file = tmp_file
medium.save!
end
Transaction will automatically delete (unlink) the temporary file after block
finish. If you want to keep the tmp file for longer you can use:
file = PullTempfile.pull_tempfile(url: url, original_filename: original_filename)
# ...
file.unlink # delete file
License
The gem is available as open source under the terms of the MIT License.
Reason why this Gem exist:
When you using gem like 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
# ...
: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