Reputation: 2137
This is driving me nuts. Im using CarrierWave with Amazon S3, I can safely upload a file to the bucket, and Im trying to now (in a different request) retrieve the file and deliver it as a download to the browser.
The files can be anything, .zip file etc. Im not using it for image storage.
The Bucket is private, not public so I can't just use the S3 URL.
Here's my retrieve code:
au = @note.attachment
au.retrieve_from_store!(File.basename(@note.attachment.to_s))
au.cache_stored_file!
The code errors on the cache_stored_file! line. Throwing the error:
undefined method `body' for nil:NilClass
I inspect the object and it looks fine to me, and if I output @note.attachment, I can clearly see the amazon s3 URL with keys etc.
Iv been all over the web and I can figure it out. Iv found a handful of people with the same issue who solved it by doing things that are irrelevant to my case (like using some imagemagick method), again, these are just files.
No handling or image work, I just want to return the files to the browser as a download.
Can anyone please help?
Here is my uploader:
class AttachmentUploader < CarrierWave::Uploader::Base
storage :fog
def store_dir
"#{Rails.env}/#{model.id}"
end
def cache_dir
"#{Rails.root}/tmp/attachments"
end
end
and the trace
carrierwave (0.8.0) lib/carrierwave/storage/fog.rb:225:in `read'
carrierwave (0.8.0) lib/carrierwave/uploader/cache.rb:77:in `sanitized_file'
carrierwave (0.8.0) lib/carrierwave/uploader/cache.rb:116:in `cache!'
carrierwave (0.8.0) lib/carrierwave/uploader/cache.rb:73:in `cache_stored_file!'
Upvotes: 3
Views: 5182
Reputation: 4555
I think these lines don't make sense:
au = @note.attachment
au.retrieve_from_store!(File.basename(@note.attachment.to_s))
au.cache_stored_file!
retrieve_from_store
is something you would typically call on the uploader, not on the attached object. The complicated step of passing the basename of the attachment to itself should make warning bells go off all over.
If I understand you correctly you simply want to give the user the possibility to download the file that you stored in S3.
You can do this is in a couple of ways.
The easiest is to call @note.attachment.url
and print the url as a link that your user can click.
Another way is to redirect the user to the url in controller action.
# notes/1/download_attachment
def download_attachment
@note = Note.find(params[:id)
redirect_to @note.attachment.url
end
One last way is to act as a proxy server/cache, and fetch the file from S3 and return it.
You could do it something like this in your controller:
file = open(@note.attachment.url)
send_data file
Please note that I didn't have the chance to test this last code snippet.
You can read more about send_data here.
Upvotes: 4