Rails Form Drag and Drop Photo Uploader Carrierwave

Let's say that we have a Track application designed to display a gallery of paintings. To add together a painting to the gallery we have a form with a text field to give the painting a name and a standard file upload field.

The page for adding a painting.

When we submit this form our prototype is resized, cropped and added to the gallery. The file upload is handled by CarrierWave which we covered in item in episode 253. We take a Painting model with a call to mount_uploader and which is passed an ImageUploader class, a subclass of CarrierWave::Uploader::Base.

            course            Painting            <            ActiveRecord::Base            attr_accessible            :prototype,            :name            mount_uploader            :image,            ImageUploader            end          

The uploader form is a fairly standard uploader. Information technology creates a thumbnail version that resizes the paradigm using RMagick and this version is displayed on the gallery page.

            class            ImageUploader            <            CarrierWave::Uploader::Base of operations            include            CarrierWave::RMagick            # Include the Sprockets helpers for Track 3.ane+ nugget pipeline compatibility:            include            Sprockets::Helpers::RailsHelper            include            Sprockets::Helpers::IsolatedHelper            storage            :file            def            store_dir                          "              uploads/                              #{model.grade.to_s.underscore}                            /                              #{mounted_as}                            /                              #{model.id}                            "                        finish            def            extension_white_list                          %due west(              jpg jpeg gif png              )                        end            version            :thumb            practise            process            resize_to_fill:            [200,            200]            stop            finish          

Improving The Uploader

The issue with our awarding is that we tin only upload one painting at a fourth dimension. It would exist better if we could upload multiple images at once from the primary gallery page then we'll implement this. We want a file upload button on the gallery page that allows us to select multiple images then to start we'll replace the link to the new painting page with a form where we tin can upload multiple images at one time.

            <h1>Painting Gallery</h1>            <div            id=              "              paintings              "                        >                          <%=              return              @paintings              %>                        </div>            <div            form=              "              clear              "                        >            </div>                          <%=              form_for              Painting.new              do              |f|              %>                                      <%=              f.label              :image,                              "                Upload paintings:                "                            %>                                      <%=              f.file_field              :image              %>                                      <%              end              %>                      

If we reload the gallery folio at present we'll see the course but its file upload field will merely permit us to select a single painting. We can fix this by passing the multiple option to our file_field and setting it to true.

                          <%=              f.file_field              :image,              multiple:              true              %>                      

At present, in some browsers at least, nosotros can select multiple images in the file upload dialog. There is an issue with this, yet. If we view the source for the form field nosotros'll see that the proper name of the file input field has a pair of foursquare brackets at the end. This means that the images are submitted as an array to our Runway application.

            <input            id=              "              painting_image              "                        multiple=              "              multiple              "                        name=              "              painting[image][]              "                        type=              "              file              "                        />          

Unfortunately this causes some issues with CarrierWave and we'll need to prepare it. At that place are a number of dissimilar ways that nosotros can handle this situation, the simplest is to difficult-lawmaking the name of the field.

                          <%=              f.file_field              :image,              multiple:              true,              name:                              "                painting[image]                "                            %>                      

If we change the proper name of the Painting model or its image attribute we'll demand to think to change the name of this aspect, as well merely with this change in identify there'll no longer exist foursquare brackets at the end of the file field's name and any images we upload won't be sent in an array. We now accept some other problem, however, in that if we do upload multiple files only one of them will be used to create a painting. This is where a JavaScript library can come up to our help and allow us to upload multiple files at in one case. We'll use the jQuery File Upload which is a polished solution that allows us to upload multiple files at one time. With it nosotros can select a number of files then click a 'get-go upload' push button to upload the files and it will even show upload progress bars while the files are uploading.

At that place are a couple of dissimilar means that we can set up this up. The first option is known as the UI version and this works well if we simply need a quick way to get a file upload, although it works best with Twitter Bootstrap and makes a lot of decisions for united states of america. The other option is a minimal setup which uses the basic upload functionality and which leaves the user interface up to u.s.. This mode we can customize it farther and brand it fit and integrate with our existing interface and it's what we'll using in this episode.

We demand to integrate this library into the Rails nugget pipeline and for this we'll exist using the jQuery FileUpload Rails gem. This gives united states several files that we nosotros can crave to add its functionality to our awarding. To utilize it we'll add it to the assets group of our Rails application then run bundle to install it.

group            :assets            practice            gem                          '              sass-rails              '            ,                          '              ~> three.2.3              '                        gem                          '              coffee-rails              '            ,                          '              ~> iii.2.i              '                        # Run across https://github.com/sstephenson/execjs#readme for more supported runtimes            # gem 'therubyracer', :platforms => :ruddy            gem                          '              uglifier              '            ,                          '              >= i.0.3              '                        gem                          '              jquery-fileupload-runway              '                        end          

Next we'll alter the application'due south JavaScript manifest file to add the jquery-fileupload/basic as demonstrated in the README.

            //= crave jquery-fileupload/basic          

We still need to add this functionality to the file upload course on the paintings page and we'll do this inside the paintings CoffeeScript file.

jQuery ->   $('#new_painting').fileupload()

All nosotros need to do here is call fileupload() on the new paintings class after the DOM has loaded. When we reload the page now our file upload form has some extra functionality, although it looks the same. If nosotros use the file command to select several files null appears to happen, although if we refresh the folio subsequently we'll see that the images nosotros selected have been uploaded.

The images appear when we refresh the page.

Information technology'due south important to understand that when we select multiple files the form is submitted in one case for each file. This triggers the PaintingsController's create activeness for each file, creating a new Painting tape each time. Nosotros'd like the new paintings to be shown in the gallery as presently as they're uploaded without the user needing to upload the folio. To accomplish this we first demand to customize the file uploader. This accepts various options and we'll apply the dataType selection here.

jQuery ->            $(              '              #new_painting              '            ).fileupload     dataType:                          "              script              "                      

The dataType option determines the type of information that the uploader expects dorsum from the server. About examples will return JSON but this means that our Rails awarding will need to generate some JSON and that we'd also demand to write some JavaScript code to render the new paintings in the gallery. This approach usually leads to duplication on the customer and server and it can be easier in these situations to work with JavaScript instead. Using script as the information type means that we tin can return a script from the server and it will be executed afterward the file uploads. This means that nosotros demand to change the PaintingsController'southward create action so that it returns some JavaScript. While we could support both HTML and JavaScript formats we'll keep things elementary and just employ a JavaScript template. First we'll change the controller and so that information technology but creates a new Painting record.

            def            create            @painting            =            Painting.create(params[:painting])            terminate          

Side by side nosotros'll create a new JavaScript template for this action.

                          <%              if              @painting.new_record?              %>                        alert("Failed to upload painting:                          <%=              j              @painting.errors.full_messages.join(                '                ,                                '              ).html_safe              %>            ");                          <%              else              %>                        $("#paintings").append("              <%=              j return(@painting)              %>            ");                          <%              terminate              %>                      

This template is fairly simple. Offset we cheque to meet if the painting is a new record. If this is the case then the validations have failed and so we'll brandish an alert that shows the validation error messages. If the painting is saved successfully nosotros'll append the rendered partial for the painting to the paintings div so that it's added to the gallery. We tin try this out now by reloading the page then adding a couple of files. We'll utilise another feature of jQuery File Upload to do this and drag and drop the images instead of using the file upload dialog. When we practice so the new images automatically announced in the gallery without us having to reload the page.

The pictures are now automatically added to the page.

There are some layout issues on the page and these are primarily because the paintings that nosotros've but uploaded don't have names. This is a common trouble when dealing with multiple file uploads equally the user isn't inbound any other information about the uploaded files. To piece of work around this we can fix some default values based on the files that are uploaded. We'll add a before_create callback which will set a default name for each file based on its filename.

            form            Painting            <            ActiveRecord::Base            attr_accessible            :image,            :name            mount_uploader            :image,            ImageUploader            before_create            :default_name            def            default_name            self.name ||=            File.basename(image.filename,                          '              .*              '            ).titleize            if            image            stop            end          

Now when we upload a file its name is prepare automatically.

Adding Progress Bars

And then far the files we've been uploading appear almost instantly every bit we're running our awarding on the local machine. If nosotros were running it across a slow connection then it could be minutes before the files appear in the gallery so nosotros should provide some feedback to the user during this time. We'll do this by showing a progress bar for each image immediately after the user chooses the files to upload. This will need to exist all on the client which ways that for convenience it would be nice if nosotros had some mode to render a client-side template. To exercise this we'll go dorsum to the JavaScript manifest file and add another require statement to it.

            //= require jquery-fileupload/vendor/tmpl          

This library is included within the jQuery File Upload precious stone and it will easily allow us to render out a template which is embedded inside the HTML. We'll paste the code for the template at the bottom of our alphabetize action.

            <script            id=              "              template-upload              "                        type=              "              text/ten-tmpl              "                        >            <div            form=              "              upload              "                        >            {%=o.name%}            <div            grade=              "              progress              "                        >            <div            course=              "              bar              "                        style=              "              width: 0%;              "                        >            </div>            </div>            </div>            </script>          

We've added a script chemical element hither with a blazon of text/x-tmpl. We can add some HTML inside this element that nosotros tin render on control through JavaScript and use special tags to reference an object that's passed in and add dynamic content. The residuum of the code in hither is just some divs to handle displaying the progress bar. Next we'll add add and progress options to fileupload to render the template.

jQuery ->   $('#new_painting').fileupload     dataType: "script"     add: (e, data) ->       data.context = $(tmpl("template-upload", data.files[0]))       $('#new_painting').append(data.context)       data.submit()     progress: (east, data) ->       if information.context         progress = parseInt(information.loaded / data.total * 100, ten)         data.context.find('.bar').css('width', progress + '%')

The add pick is passed a function and this is triggered when a new file is added. Each carve up file that is uploaded volition trigger this office and it's passed a information object that we can use to fetch various data such as the file object that we can pass to the template which we reference by the id we gave it. Calling tmpl will return this template and we pass this to the jQuery function, $. We prepare the information.context to the result of this so that we can reference it later. Nosotros then append the template to the new_painting course then phone call data.submit to trigger the uploading of the file.

The progress callback updates a the progress bar. Outset we check that the information context that we set in add exists; if it does and so we find the progress bar and set its width depending on the electric current progress of the uploaded file.

We can endeavor this out at present. We've removed all the pictures from the gallery so that nosotros've got a make clean slate to start from. If we drag and drop a couple of pictures into the browser window we'll run into a progress bar for each one.

A progress bar is now displayed for each image we upload.

If we upload a file that isn't a valid image file, say a zippo file, we'll see an alert message later the file has uploaded and it isn't a valid file type. It would be amend if we did the validation on the customer before it was uploaded to save the time and bandwidth it takes to upload. We can practice this quite hands by changing the add callback office to this:

jQuery ->   $('#new_painting').fileupload     dataType: "script"     add together: (e, information) ->       types = /(\.|\/)(gif|jpe?g|png)$/i       file = data.files[0]       if types.test(file.type) || types.test(file.name)         data.context = $(tmpl("template-upload", file))         $('#new_painting').append(information.context)         data.submit()       else         alert("#{file.name} is not a gif, jpeg, or png image file")     progress: (due east, information) ->       if data.context         progress = parseInt(data.loaded / information.total * 100, x)         information.context.find('.bar').css('width', progress + '%')

Now nosotros cheque that file's type or proper noun matches a regular expression that matches a number of mutual image types before we upload it. If information technology doesn't match we'll show an fault message instead of uploading the file. Now if we try to upload something like a nada file it won't exist uploaded and we'll see a validation error bulletin straight away.

Our example is pretty much complete at present. We take a gallery where we can upload files by drag-and-driblet and nosotros have a progress bar that shows the progress of each file as it uploads. To acquire more about jQuery File Upload it's worth taking a expect at its wiki4, particularly the options page which includes a lot of information nearly the options that nosotros pass in to the uploader. In that location'south also some information about setting Rails upwards with the UI version of jQuery File Upload.

mcclellandtakether.blogspot.com

Source: http://railscasts.com/episodes/381-jquery-file-upload?view=asciicast

0 Response to "Rails Form Drag and Drop Photo Uploader Carrierwave"

Post a Comment

Iklan Atas Artikel

Iklan Tengah Artikel 1

Iklan Tengah Artikel 2

Iklan Bawah Artikel