Upload video files with progress bar using Rails, Paperclip and Javascript

Rails does not help much when dealing with AJAX uploads by means of external JS libraries. I recently came across a case where a user on www.codementor.io was struggling to use JQuery-upload-file to upload a video to a Rails backend. The main reason to use the library was the progress bar feature, something that is missing in the Rails world. In this blog post I'll show you how to implement the functionality in the simplest case possible.

The interface looks as follows:
Screen Shot 2015-05-24 at 10.54.59

The view looks like follow:

As you can imagine there is a Movie model in the backend ready to be created. The data: { disable_with: 'Uploading' } bit will disable the button when we submit our form. The actual form submission will be handled by jquery-upload-file.

On the JS code this is what we need now:

This is far from perfect, but bear with me for the sake of this example. Javascript is populating the formData with the form parameters which will arrive to the backend together with the video. When the user click the submit button we do the following: (i) we avoid the default form submission with e.preventDefault() and (ii) we disable the button for multiple submissions with $.rails.disableFormElements($($.rails.formSubmitSelector));

The create action in the controller looks as follows:

A gotcha to keep in mind is that we do not use redirect_to here because we want the JS code to handle the redirection explicitly. This is why we return the new path in the JSON response. The create action is taking the parameters from the request and attaching the video to the model using the paperclip and paperclip-av-transcoder gem.

This is an example of parameters that we receive in the controller:

The model will have the following (magic) code to attach the video:

Finally the controller simply returns a JSON object with the url for the next page where the user should be redirected after the upload is done. The JSON is picked up by the onSuccess() callback of the the jquery-upload-file library. At this point a simple window.location.href will do the trick.

Hope it is useful,
Enjoy

Disclaimer: This blog post covers the fastest way to have a progress bar for file uploads working on Rails. However I highly encourage you to allocate time for more configurable and maintainable solutions likes this one http://www.sitepoint.com/asynchronous-file-uploads-rails/


Also published on Medium.

15 thoughts on “Upload video files with progress bar using Rails, Paperclip and Javascript

  1. I don't understand... You use: $('#movie_description') but I don't find that id anywhere in the view. Where did you put it?

    Also, if my upload needs to be associated with an user, how can the app know which user is currently logged in? I had a hidden field to put there the member_id but that's not the best way for sure :X

    1. Hi Rui,

      You use: $('#movie_description') but I don't find that id anywhere in the view. Where did you put it?

      By convention the Rails form_for generates this id for the view. It is weird that you don't find it. Are you using the same code I posted?

      Also, if my upload needs to be associated with an user, how can the app know which user is currently logged in? I had a hidden field to put there the member_id but that's not the best way for sure :X

      Usually to keep track of the current user you rely on external gems like Devise. If you don't want to go the gem way you can always keep the user_id in the session object of Rails. Check http://stackoverflow.com/questions/12719958/rails-where-does-the-infamous-current-user-come-from

      Let me know if I can help further!

  2. Thank you for your tutorial first
    However, I come cross a problem that nothing happens, when I click submit button .
    I think the problem is that the upload ajax form created by the plugin just doesn't submit properly, but I don't know how to solve it.
    Any help would be appreciated

      1. Above are all my code, only the model changes from your movie to this pin.
        f.input :image, input_html: { class: 'form-control'} This statement create a simple input, but I can see a rather complex div in HTML through Chrome Devtool.
        So I conclude that the plugin initial statement works. And my problem is that when I click the submit button, nothing happens. No request incoming in my rails log, only the button being disabled.

          1. Hi daorren,

            have you checked if using a normal form instead of simple_form changes anything?

            I see nothing obvious in there, but the problem is definitely in the frontend.
            Hope this helps,
            Alfredo

          2. I have done mainly 2 things to make things work

            First, instead of using 'm.file_field :video'
            I just use a empty div, for the plugin to do its work

            Secondly, making some changes to the variables in js
            we shouldn't use formData, or it would always be empty, because it's called when the dom is loaded. Instead we should use dynamicFormData, as the project maintainer mentioned when he answer others' questions
            and we should use val() instead of text() in form

Leave a Reply

Your email address will not be published. Required fields are marked *

Answer the question * Time limit is exhausted. Please reload CAPTCHA.