Basic file uploading in Rails - ruby-on-rails

I'm having a lot of trouble finding a solution to uploading a file to a folder in Rails.
I have a file that I need to upload to a specific folder in the app 'public/uploads' with a specific name. Each time i upload, i need to run a pre-existing background job, which will remove the file after it's done.
If it happens that a file already exists, it should just overwrite it.
I can't find a solution that covers this. All the examples are things about attaching a file to an instance of a model and storing it in my DB. I don't need that. That's overkill for my scenario.
Just upload file to a folder, simple as.
Suggestions?

You can modify the file path. The easiest strategy is to add a randomly generated or sequential subfolder/filename prefix for each upload.
So Rails.root.join('public', 'uploads', uploaded_file.original_filename) becomes Rails.root.join('public', 'uploads', "#{my_random_value}-#{uploaded_file.original_filename}").

Related

Rails file upload: upload a folder

I work on Rails project and client asked if I can add 'upload a folder' feature to simple file upload system that we have now. Currently it attaches files to model and then displays them on a page for download. Pretty basic.
But I can't figure out how can I handle folder uploads, with every folder having it's own content. Is there any pre-made gems that can help accomplish that?
We use Paperclip at the moment, but I don't mind migrating to Carrerwave or some other gem that would
UPDATE I see that I was unclear about my needs. I need an upload system that could handle folders. Something like this.
In Dropbox I am able to upload both files and folders. How can I make my uploaders accept folders and then display them alongside regular attached files?
you can solve it by using the interpolation of paperclip where you can create or naming the folder dynamically for the same you need to do like below
specify the path into model which you wanted always
:path => ":folder/:id_:filename"
and specify the private method in same model or using globally specify in initializer
Paperclip::interpolates :folder do |attachment, style|
attachment.instance.name
end

Local file upload: File.open or StringIO

My application allows a user to upload an image and then create different versions of that image (e.g. aligned and cropped with another image). The intermediate step is that I need to copy the uploaded file to another object and process it. The easiest way to do this is to upload it locally.
From the carrierwave wiki, they suggest using a modified version of StringIO.
On the carreirwave readme, they also suggest using File.open (something like obj.image=File.open('path_to_file').
I've also found references to using fixture_file_upload from ActionDispatch::TestProcess (usually in testing, but I'm unsure why it is restricted to that environment).
Can anyone give me a good explanation on the pros and cons (if any) of using these methods?
Thanks.
I just discovered one major difference, at least in the context of carrierwave. If you use carrierwave with the move_to_cache option set to true and mount your upload column with File.open, the file given to File.open will be moved, while with StringIO, it won't.

Strategy for avoiding file upload naming conflicts

I have a webapp in Rails which as an AJAX file upload feature. Files are uploaded to a remote server (AWS S3). My current strategy is to upload the files in a temp/ directory (with their original name) until the user submits the form, and then rename them to their definitive name.
But the problem is that if multiple users try to upload two files with the same names at the same time, then one is gonna override the other.
The strategy I was thinking of to solve this was to generate random SHA1 when the upload page is loaded, store them in a table locally to make sure they're unique, and remove them when the temp file is renamed.
Do you see problems with this approach?
What's a good strategy to solve this problem?
One problem is, if they navigate away from the page without uploading anything, their hash will stay in the database, and eventually make a mess. I would avoid storing anything this temporary in the database.
Rather than try to come up with your own way to name temporary files, why not use the ruby tempfile library, which will do it for you?
Originally, I thought you were uploading the files to the ruby server, and uploading them to s3 yourself. Tempfiles won't help if users are uploading files directly. If you just want unique names for your temp files, a UUID generator might work for you. There is a Ruby UUID generator gem which is designed to not produce duplicates, even in a distributed setting. If you name your files with these, you shouldn't need to store anything in the database.

Extracting uploaded archive to S3 with CarrierWave on Heroku

I want to do something what I thought will be a simple task:
Have a form with these controls:
File upload for one file
Checkbox if this file should be extracted
Text input where I would specify which file should I link to (required only if the checkbox is checked) - index_file
After submitting form:
If the checkbox isn't checked, upload the file via CarrierWave to S3 to the specified store_dir
If the checkbox is checked, extract all files from the archive (I expect only ZIP archives; I need to keep the directory structure), upload extracted files to the specified store_dir and set the index_file in database (I don't need to save to database anything about other extracted files)
As I have found, it isn't an easy task because of Heroku limitations. These files will have a large size (hundreds of MiBs or a few GiBs), so I don't want to redownload this file from S3 if possible.
I think that using Delayed Job or Resque might work, but I'm not exactly sure how to do it and what is the best solution of my problem.
Does anyone have any idea how to solve it with using the lowest resources as possible? I can change CarrierWave to another uploader (Paperclip etc.) and my hosting provider too if it isn't possible on Heroku.
I was also thinking about using CloudFlare, would this still work without problems?
Thank you for answers.
Based on this heroku support email, it would seem that the /tmp directory is many gigs in size. You just need to clean up after yourself so Heroku as a platform is not the issue.
A couple of articles may help you solve the problem:
https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Make-Carrierwave-work-on-Heroku - which explains how to configure your app to use the /tmp directory as the cache directory for CarrierWave. Pay attention to the following line:
use Rack::Static, :urls => ['/carrierwave'], :root => 'tmp' # adding this line
This instructs rack to serve /carrierwave/xzy from the /tmp directory (useful for storing images temporarily)
Then, using the uploader.cache! method, you can deliberately cache the inbound uploaded file. Once stored, you can do checks to determine whether to call the uploader.store! method which will promote the contents to S3 (assuming you configured S3 as the store for CarrierWave.

Using Paperclip to Process .tga (targa) Files

I've run into an annoying problem with Paperclip. Paperclip is working fine for uploading jpg/gif files but it's choking on .targa files with the error "not recognized by identify”. Just to confirm, it's working 100% with jpg/gif/png files and I have imagemagick installed and working, this error only occurs with .tga files.
The general process for paperclip is:
User uploads a file
Tempfile is created containing the contents of that file
The identify command is run on the Tempfile to get the width/height of the image.
With jpg/png/gif files, identify can run on file without needing a valid extension (eg .jpg) to be able to recognise the file type. However, when identifying a .tga file, it requires the ".tga" extension in the file name.
The problem is this:
When Paperclip creates the temp file, it creates with a name similar to: stream.0.1. Because this tempfile lacks the .tga extension, the identify command can not parse the dimensions of the image, thus causing the "not recognized by identify”.
I'm not sure how to go about fixing this, the best idea I can come up with is to use the regular File.new command rather than Tempfile.new to create the temporary file with a random name but the correct file extension. This would require also patching in custom code to remove the Files after processing has been done rather than relying on Ruby's inbuilt ability to delete tempfiles after use.
Does anybody have some ideas on the best method I could go about fixing this?
This was a bug in Paperclip and has been fixed. More details can be found here:
http://groups.google.com/group/paperclip-plugin/browse_thread/thread/7fd7a8d7bab696a7

Resources