The Dragonfly gem is a really efficient way for a rails project to support on the fly image resizing and processing. If you haven’t given it a try yet, I highly recommend you do. Today I will be looking into how to show a nice preview image. Image preview are important because they allow the user to confirm the file they selected as well as show how the image will be cropped.
GOAL:
The usual way to do this is via Ajax. A great example of this can be found by the good people at Zurb. There are many problems with the Ajax solution. Namely, what happens when the form’s validations fail (bad email, etc…). Ideally you should still be able to see the image you uploaded without having to re-upload it! Moreover, sometime the user will not complete the form successfully. In this case the image he uploaded should be removed. This is where Drangonfly comes to the rescue! Say you have a profile image on your user model. You would need to create a profile_image_uid column in the database. Dragonfly would then provide you with a `retained_profile_image` form helper to remember the image in case of validation errors. The solution goes as follows:
1) Create an iframe containing only the file input tag
2) When this input changes (when the user selects a file) automatically upload it to the server (right away! ie: don’t wait for the form to submit)
3) Reload the iframe with javascript which will change the retained_profile_image value (as if the form had been submitted with an error) and show the image
Now when the form is submitted, Dragonfly will use the value in retained_profile_image to get the image without having to re-upload it! If the form fails, the retained_profile_image will stay. If the user leaves the page (or uploads another image), Dragonfly will automatically remove the temp image!
Here is the code:
def preview if params[:image].present? app = Dragonfly[:images] uid = app.store(params[:image].tempfile) @image = app.fetch(uid) @retained_image = Dragonfly::Serializer.json_encode(uid: @image.uid) if @image end render layout: falseend<%= form_tag="" image_preview_path,="" multipart:="" true,="" id:="" "image_preview_form"="" do="" %=""><%= file_field_tag="" :image="" %=""><% end="" %=""><script> //automatically submit the form document.getElementById("image").onchange = function() { document.getElementById("image_preview_form").submit(); }; <% if @image %> //update the retained image field window.parent.document.getElementById("user_retained_profile_image").value = "<%= @retained_image %>" window.parent.document.getElementById("user_photo").src = "<%= @image.thumb('145x145#').url %>" <% end %></script><%= simple_form_for="" @user,="" ...="" %=""><div><label> Upload a photo </label><iframe width="600" height="50" frameborder="0" src="”<%=" image_preview_path="" %="">” /><% if="" f.object.profile_image.present?="" %=""><%= image_tag="" f.object.profile_image.thumb('145x145#').url,="" class:="" 'user_photo'="" %=""><%= f.input_field="" :remove_profile_image="" %=""><% else="" %=""><%= image_tag="" 'default.png',="" size:="" '145x145',="" class:="" 'user_photo'="" %=""><% end="" %=""><%= f.input_field="" :retained_profile_image,="" as:="" :hidden="" %=""></%=></%></%=></%></%=></%=></%></iframe></div><% end="" %="">get 'image_preview', to: "image#preview"post 'image_preview', to: "image#preview"</%></%=></%></%=></%=>
Of course this code can be improved, for instance to show the upload progress to the user. For those using simple_form, I’ve turned this code into a gem. Have you ever used the Dragonfly gem? Feel free to ask any questions or share your experiences with image preview in the comments.
Smashing Boxes is a web and mobile app development company know for creating a lasting experience through bold design and disrupting the status quo. We are entrepreneurs and craftsmen first, and a digital creative agency second. Inspired by our visionary clients, we transform ideas into innovative web and mobile applications. Take a look at our work.