Download a Carrierwave upload from S3 - ruby-on-rails

I'd like to download an image that was uploaded to S3 using carrierwave. The image is on the Card model, mounted as an uploader. I saw this answer, but had trouble getting that solution to work. My code is:
#download image from S3
uploader = card.image #image is the mounted uploader
uploader.retrieve_from_store!(File.basename(card.image.url))
uploader.cache_stored_file!
that last line throws: "... caused an exception (undefined method `body' for nil:NilClass)..."
My carrierwave config looks like:
#config/initializers/carrierwave.rb
CarrierWave.configure do |config|
config.storage = :fog
config.cache_dir = "#{Rails.root}/tmp/upload"
...
end

Thanks apneadiving. It was as easy as:
image = MiniMagick::Image::open(card.image.to_s)
image.write(somepath)

I have tried this in Rails 5 to download file from AWS S3.
def download
image = card.image
# validate existing image from AWS S3
if image.try(:file).exists?
data = open(image.url)
send_data data.read, type: data.content_type, x_sendfile: true
end
end
I hope help everyone.

Related

Carrierwave upload and access file on S3

I am struggling to access files on S3 with Carrierwave.
In my uploader file doc_uploader.rb I have the following code
storage :file
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
to uplooad "doc" model defined as follow
class Doc < ActiveRecord::Base
belongs_to :user
mount_uploader :doc, DocUploader
end
To access the uploaded file I have the following line of code in a controller
#doc = current_user.docs.order("created_at").last #last file uploaded by user
io = open("#{Rails.root}/public" + #doc.doc.url)
Everything works perfectly locally. Now I want to move my file to S3 in the uploader I use fog and replace
storage :file
by
storage :fog
I adjust my config file carrierwave.rb and uploading works perfectly. However, to access the file I try to use
#doc = current_user.docs.order("created_at").last
io = open("#{#doc.doc.url}")
and I get the following error
No such file or directory # rb_sysopen - /uploads/doc/doc/11/the_uploaded_file.pdf
Could anyone give me the right syntax to access the file on S3 please? Thanks.
When accessing the asset through the console, it gives you only the path, you might need to append the protocol & host to the #doc.doc.url, something like:
io = open("http://example.com#{#doc.doc.url}")
Or you can set the asset url on the environment you need to, but this is not really necessary:
config.asset_host = 'http://example.com'
This only applies if you are using the console, on any web view this will not apply, carrierwave seems to handle it

Carrierwave fog local storage full attachment path

I am building a rails app with carrierwave and fog for attachment storage. In my test environment, I am using fog local storage.
I am looking for a way to get the full attachment path with this configuration.
CarrierWave.configure do |config|
config.fog_credentials = {
provider: 'Local',
local_root: '/Users/me/fog',
endpoint: '/Users/me/fog',
}
config.fog_directory = 'test.myapp.com
config.fog_public = false
config.fog_attributes = { 'Cache-Control' => 'max-age=315576000' }
end
When I use any other storage options (like AWS S3), I can get the full url to an attachment just by doing my_object.my_attachment_url or my_object.my_attachment.path.
However, when using Local storage, I only get a relative path to my configuration options like my_object/my_attachment/1/test.jpg.
Is there any way through carrierwave or fog to get the full path to this local file?
For my example, the output I am looking for would be: /Users/me/fog/test.myapp.com/my_object/my_attachment/1/test.jpg
For me, the answer was modifying to carrierwave uploader class.
I had
def store_dir
"#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
which worked fine for AWS S3 as all the S3 specific info was inserted before this string. However, to get this to work with fog Local as well, I added:
if Rails.env.test?
def base_path
"#{File.expand_path(CONFIG.fog_local_root)}/#{CONFIG.fog_directory}/"
end
else
def base_path
''
end
end

CarrierWave Backgrounder not uploading versions images to AWS S3

I was using carrierwave 0.10.0 gem with RMagic to upload images on AWS S3. Everything was working fine except it was taking too much time to upload on AWS S3. So thought using carrierwave backgrounder to upload images in background. I set up carrierwave backgrounder (0.4.2) but In this one My original file is always get upload to S3 but versions of that image is never gets uploaded on S3.
Here is my carrierwave_backgrounder.rb
CarrierWave::Backgrounder.configure do |c|
c.backend :sidekiq, queue: :carrierwave
end
I have defined my queue in sidekiq.rb
Sidekiq.configure_server do |config|
config.redis = { :url => "redis://#{ENV['REDIS_ENDPOINT']}:6379", :namespace=> "#{ENV['REDIS_NAMESPACE']}" }
config.options =
queues: %w{
critical
carrierwave
}
})
end
Here is my photo_uploader.rb
class PhotoUploader < CarrierWave::Uploader::Base
include ::CarrierWave::Backgrounder::Delay
include CarrierWave::RMagick
storage :fog
def store_dir
"uploads/images/"
end
def filename
"#{secure_token}.#{file.extension}" if original_filename.present?
end
def orient_image
manipulate! do |img|
img.auto_orient
img
end
end
# Create different versions of your uploaded files:
version :thumb_small do
process :resize_to_fill => [100,100]
process :strip
end
def strip
manipulate! do |img|
img.strip!
img = yield(img) if block_given?
img
end
end
def extension_white_list
%w(jpg jpeg gif png)
end
def get_version_dimensions
model.width, model.height = `identify -format "%wx%h " #{file.path}`.split(/x/)
end
protected
def secure_token
var = :"##{mounted_as}_secure_token"
model.instance_variable_get(var) || model.instance_variable_set(var, SecureRandom.hex(5))
end
end
Here is my profile.rb file
mount_uploader :image_url, PhotoUploader
process_in_background :image_url
I have started the sidekiq worker using this command
bundle exec sidekiq -d -L log/sidekiq.log -C config/sidekiq.yml -e development
When I upload image_url only the original image is uploaded. This is sidekiq log after uploading original file. But I don't see any version file uploaded. I checked the S3 bucket also(No version file only the original file)
2016-01-11T08:52:20.772Z 3983 TID-ownpyrrxk CarrierWave::Workers::ProcessAsset JID-91e3803d50defb2d1419cef1 INFO: start
2016-01-11T08:52:31.119Z 3983 TID-ownpyrrxk CarrierWave::Workers::ProcessAsset JID-91e3803d50defb2d1419cef1 INFO: done: 10.347 sec
Is There something I am missing. Please Help
Thanks in Advance
After investigating with few documentations, here is my suggestion:
From careerwave_backgrounder readme: https://github.com/lardawge/carrierwave_backgrounder#background-options
Its clearly shows,
# This stores the original file with no processing/versioning.
# It will upload the original file to s3.
From this #113 , the author said
I found a bug related to Rmagick but no issue with versions
You can try with MiniMagick/ImageMagick instead of RMagick.
Documentation to look for the similar issue:
https://github.com/lardawge/carrierwave_backgrounder/issues/113
https://github.com/lardawge/carrierwave_backgrounder/issues/130
Rails CarrierWave versions are not created for some reason
Thanks!

Delete original file after using carrierwave gem to upload

I am using carrierwave to upload and process a file. After the process is done I want to be able to delete the original file. I put
after :store, :unlink_original
def unlink_original(file)
return unless delete_original_file
file.delete if version_name.blank?
end
in my uploader. I also added
class CarrierWave::Uploader::Base
add_config :delete_original_file
end
CarrierWave.configure do |config|
config.delete_original_file = true
end
to my config/initializers/carrierwave.rb:
The original file is still in the directory along with the processed file. How would I go about deleting this file the right way after carrierwave is done with it?

How to send file to user with carrierwave?

Here's my old code to sends a file to the browser:
def show
send_file File.join(Rails.root, 'tmp', 'price.xls')
end
But recently I've found out that tmp folder can't be used as a persistent storage on Heroku, so I decided to move the file to AWS S3.
That's what I've got so far:
def show
uploader = PriceUploader.new
uploader.retrieve_from_store!('price.xls')
end
Now, how do I send the file to the browser?
upd
I itentionally didn't mount the uploader
Figured it out.
def show
uploader = PriceUploader.new
uploader.retrieve_from_store!('price.xls')
uploader.cache_stored_file!
send_file uploader.file.path
end
In my case
# find uploader ...
send_file(uploader.path,
filename: uploader.filename,
type: "application/<some-type>")

Resources