How to use ORM (activerecord) with Carrierwave_direct? - ruby-on-rails

I'm successfully using Carrierwave_direct - it mounts an uploader and uploads directly to S3 yay! H
owever, unlike Carrierwave it does not persist a record into the DB - rather it just redirects back to a 'success_path' (standard AWS/S3 function).
Before embarking on rolling my own solution I'm curious if anyone has figured this out or has a good approach for this. I would like it to upload directly to S3 and use carrierwave to persist the record to the db.
My immediate thoughts are to pass params to the process which get carried back to the app - then grap these params and create the record.
Appreciate any thoughts.

All you have to do is:
giving the page you want to go back on success in the new action of your controller: #uploader.success_action_redirect = 'Your_update_page'
Amazon will bring you back to this page on success and add a 'key' argument in which you will have the information you need to update the db.
This is very well explained on the github readme of carrierwave direct.

Related

Retrieving Images Off Rails API That Used Paperclip and S3 to Handle Upload

I'm working on a project that uses a Rails API for the backend and has a separate front end calling on that API. This is the first project where I've had to store images on the API and after days of research on best practices, I'm now more confused than I was going into it. Basically, I use Paperclip and S3 to handle uploading images onto the API, but I've hit a roadblock now that I'm trying to call on the API to retrieve those images. I'm very new to handling images this way and don't know if I should somehow generate a url and store that in the database to call on for retrieving and displaying the images on the front end, or if there is a way to take the multiple parts of the image that Paperclip creates and generate the image from those? The API successfully calls the rest of the data like my object names and bios, I just can't figure out the proper way to store the images so I can easily retrieve them.
If you are using paperclip to upload images to amazon s3 then the object that the attatchment is associated with should have a method that is the name of whatever you set the item name as when you generated your paperclip migrations.
For example if when you generated the migration using...
https://github.com/thoughtbot/paperclip#migrations
rails generate paperclip user avatar
then this will give you the method on User called .avatar and this will in turn give you a method called .url that you can call on avatar.
i.e.
User.avatar.url
will give you the url to the location where the image is stored on S3

Rails, Amazon S3 storage, CarrierWave-Direct and delayed_job - is this right?

I've just discovered that Heroku doesn't have long-term file storage so I need to move to using S3 or similar. A lot of new bits and pieces to get my head around so have I understood how direct upload to S3 using CarrierWave-direct and then processing by delayed_job should work with my Rails app?
What I think should happen if I code this correctly is the following:
I sign up to an S3 account, set-up my bucket(s) and get the authentication details etc that I will need to program in (suitably hidden from my users)
I make sure that direct upload white lists don't stop cross-domain from preventing my uploads (and later downloads)
I use CarrierWave & CarrierWave-direct (or similar) to create my uploads to avoid loading up my app during uploads
S3 will create random access ('filename') information so I don't need to worry about multiple users uploading files with the same name and the files getting overwritten; if I care about the original names I can use metadata to store them.
CarrierWave-direct redirects the users browser to an 'upload completed' URL after the upload from where I can either create the delayed_job or popup the 'sorry, it went wrong' notification.
At this point the user knows that the job will be attempted and they move on to other stuff.
My delayed_job task accesses the file using the S3 APIs and can delete the input file when completed.
delayed_job completes and notifies the user in the usual way e.g. an e-mail.
Is that it or am I missing something? Thanks.
You have a good understanding of the process you need. To throw one more layer of complexity at you---you should wrap all of it in rails new(er) ActiveJob. ActiveJob simply facilities background processing inside rails via the processor of your choosing (in your case DelayedJobs). Then, you can create Jobs via a rails generator:
bin/rails g job process_this_thing
Active Jobs offers a few "rails way" of handling jobs...but, it also allows you to switch processors with less hassle.
So, you create a carrierwave uploader (see carrierwave docs). Then, attach that uploader to a model. For carrierwave_direct you need to disassociate the file field from your models form and move the file field to its own form (use the form url method provided by carrierwave-direct).
You can choose to upload the file, then save the record. Or, save the record and then process the file. The set-up process is significantly different depending on which you choose.
Carrierwave and carrierwave-direct know where to save the file based on the fog credentials you put in the carrierwave initializer and by using the store_dir path, if set, in the uploader.
Carrierwave provides the uploader, which define versions, etc. Carrierwave_direct facilities uploading direct to your S3 bucket and processing versions in the background. Active Jobs, via DelayedJobs, provides the background processing. Fog is the link between carrierwave and your S3 bucket.
You should add a boolean flag to your model that is set to true when carrierwave_direct uploads your image and then set to false when the job finishing processing the versions. That way, instead of a broken link (while the job is running and not yet complete) your view will show something like 'this thing is still processing...'.
RailsCast is the perfect resource for completing this task. Check this out: https://www.youtube.com/watch?v=5MJ55_bu_jM

Rails uploads for new object

When creating a new record (rails default new action), the object id is nil b/c it's unpersisted in the db.
When uploading objects, they're usually tied to an id (using paperclip).
When my user clicks on new, and I want to provide a dropzone.js area for ajax upload, how do I tie that image/file to the post object when it has no id?
If they discard or exit the browser, I would have orphaned temp images/files...
I'm having trouble connecting the dots between an object upload for a new record.
Can someone help me work out the controller logic for this? I can do it pretty easily in a separate action after the object is created, but not before.
I made a Gem to solve this kind of problem.
It works on top of paperclip and is not intrusive. To enable the functionality, you need to replace paperclip's has_attached_file with has_attached_upload.
Using Rails Pallet gem...
First, you need to upload the file to your server performing POST /uploads with file attribute. The response will give you an identifier related to that file.
Then, sending the identifier, you can update your own record. The gem will copy the file to your record after that.
This way, you can upload files before persisting your record.
You can see a full example on gem's README

Read data image, upload from web and save them in a database

I'm newest in ruby on rails developpement and i would like what is the best way to save an pictures/image from the controller of my web page. I try with something like this:
#fin = File.open(params[:photos] , "rb")
#img = #fin.read
I think you have understand my reasoning. At the end I want to be able to save my picture into my database.
I would recommend that you use a gem like carrierwave: https://github.com/carrierwaveuploader/carrierwave
You really should not save a picture into a database. Instead you should store the image on some sort of other datastore and put a pointer to it in your database. Carrierwave makes this very easy and has different adapters to store the images on your local filesystem, S3, SFTP, or NFS.
Thoughtbot's Paperclip is another good alternative: https://github.com/thoughtbot/paperclip

How can I prevent double file uploading with Amazon S3?

I decided to use Amazon S3 for document storage for an app I am creating. One issue I run into is while I need to upload the files to S3, I need to create a document object in my app so my users can perform CRUD actions.
One solution is to allow for a double upload. A user uploads a document to the server my Rails app lives on. I validate and create the object, then pass it on to S3. One issue with this is progress indicators become more complicated. Using most out-of-the-box plugins would show the client that file has finished uploading because it is on my server, but then there would be a decent delay when the file was going from my server to S3. This also introduces unnecessary bandwidth (at least it does not seem necessary)
The other solution I am thinking about is to upload the file directly to S3 with one AJAX request, and when that is successful, make a second AJAX request to store the object in my database. One issue here is that I would have to validate the file after it is uploaded which means I have to run some clean up code in S3 if the validation fails.
Both seem equally messy.
Does anyone have something more elegant working that they would not mind sharing? I would imagine this is a common situation with "cloud storage" being quite popular today. Maybe I am looking at this wrong.
Unless there's a particular reason not to use paperclip I'd highly recommend it. Used in conjunction with delayed job and delayed paperclip the user uploads the file to your server filesystem where you perform whatever validation you need. A delayed job then processes and stores it on s3. Really, really easy to set up and a better user experience.

Resources