How to Preview Uploaded Image Instantly with Paperclip in Ruby on Rails

How to preview uploaded image instantly with paperclip in ruby on rails

If I understand you correctly you want to preview an image before it is actually uploaded, right? You can do so by using some javascript.

By setting the width and height attributes of the image tag you can simulate a thumbnail.

$(function() {
$('#pictureInput').on('change', function(event) {
var files = event.target.files;
var image = files[0]
var reader = new FileReader();
reader.onload = function(file) {
var img = new Image();
console.log(file);
img.src = file.target.result;
$('#target').html(img);
}
reader.readAsDataURL(image);
console.log(files);
});
});

and the html:

<form>
<input type="file" id="pictureInput">
</form>
<div id="target">
</div>

you can check it out on code pen

How do I show a thumbnail of the uploaded image instantly using Paperclip?

Paperclip cannot show image preview instantly. Paperclip is a plugin for Ruby on Rails ActiveRecord that lets files work as simply as any other attributes do. There are no extra database tables, only one library to install for image processing, and the ease of being able to refer to your files as easily as you refer to your other attributes.

You can achieve instant image preview using javascript/jQuery. Below is the code for showing image preview.

JSFiddle Demo.

Html:

<form id="form1" runat="server">
<input type='file' id="imgInp" />
<img id="blah" src="#" alt="your image" />
</form>

JS:

function readURL(input) {

if (input.files && input.files[0]) {
var reader = new FileReader();

reader.onload = function (e) {
$('#blah').attr('src', e.target.result);
}

reader.readAsDataURL(input.files[0]);
}
}

$("#imgInp").change(function(){
readURL(this);
});

Rails: Paperclip & previews?

This kind of thing is problematic from a Rails perspective because of the way image uploads work. One strategy to make it work better is:

  • Make a sub-form for your image upload, possibly using swfupload to make it more streamlined.
  • Create a model to receive your uploads that includes some randomized access key used to retrieve and link it. Paperclip handles the attached file.
  • Use AJAX to populate your main form by inserting a hidden field, or potentially a visible check-box element with the appropriate unique_key, when the subform finishes.

A typical model looks something like this:

class Avatar < ActiveRecord::Base
has_attached_file :image
# ... Additional Paperclip options here

before_validation :assign_unique_key

belongs_to :user

def to_param
self.unique_key
end

protected
def assign_unique_key
return if (self.unique_key.present?)

self.unique_key = Digest::SHA1.hexdigest(ActiveSupport::SecureRandom.random_number(1<<512).to_s)
end
end

The reason for the unique_key field is so that you can link this in to the form of a potentially unsaved record. It is advantageous to use the unique_key instead of id when putting it in URLs since it is hard to tell if a user should be able to see this picture or not when it is uploaded since the owner user may not yet be assigned.

This also prevents curious people from altering some kind of sequential, easily guessable ID in your URL and seeing other avatars that have been uploaded.

You can retrieve the final resized thumbnail URL for the Avatar as you would any model at this point.

You can easily strip out the parameters on receipt and translate back to Avatar ID numbers:

# If an avatar_id parameter has been assigned...
if (params[:user][:avatar_id])
# ...resolve this as if it were a unique_key value...
avatar = Avatar.find_by_unique_key(params[:user][:avatar_id])
# ...and repopulate the parameters if it has been found.
params[:user][:avatar_id] = (avatar && avatar.id)
end

# ... params[:user] used as required for create or update

As people upload and re-upload images, you will eventually have a large number of orphaned records that are not actually used anywhere. It is simple to write a rake task to purge all of these after a reasonable amount of time has passed. For example:

task :purge_orphan_avatars => :environment do
# Clear out any Avatar records that have not been assigned to a particular
# user within the span of two days.
Avatar.destroy_all([ 'created_at<? AND user_id IS NULL', 2.days.ago ])
end

Using destroy_all should have the effect of purging all Paperclip material as well.

Rails 4 nested form image preview with Paperclip

I'm not sure if this is the problem, but you shouldn't have multiple HTML elements with identical IDs. Try changing the JS so that it uses the class of file fields instead.

$(function() {
$('.fileBt').on('change', function(event) {
...

Note that you probably want to rename that class to something more meaningful and specific to image upload fields. For example ".photo-upload-field" would work :)

Show image preview after selecting attachment, using Paperclip

You can't use AJAX for file uploads. Sadly browsers do not support that to be passed using an XHR. What I would suggest is to add an iframe (which is also done by all gems / plugins that allow async image upload) and add an unload to it. When the file input changes, change the target of the main form to the name of the iframe, submit it and wait for the onload of that iframe.

It would be something like this:

<iframe name="image_preview" id="image_preview" src="some_blank_page" onload="show_image_preview()"></iframe>

and

function show_image_preview() {
// read content here. Note: this function is also called when the some_blank_page is loaded!
var data = window.image_preview.document;
if (data && data.getElementById("preview")) {
// now either do something with the preview or just place the iframe so it
// is already positioned correctly
}
}

function file_field_changed() {
var form = $('..');
var original_action form.action;
form.action = "special_preview_path";
form.target = "image_preview";
form.submit();

form.action = original_action;
}

Have your special_preview_path return a preview inside a

You can also create the iframe in the onchange event and place it below each of the file input fields.

I hope this makes sense! Just let me know if you need some more info about this.

Access image from different view in a view with paperclip gem ruby on rails

Firstly, in the causes controller, pluralize @profile because Profile.all will return an array of all profiles. i.e. change @profile = Profile.all to @profiles = Profile.all

Because @profiles is an array, you need to iterate through each array item in the view Causes:

<% @profiles.each do |profile| %>
<%= image_tag profile.images.first.image.url(:thumb) %>
<% end %>

If you only intend on returning a single profile image then you will need to specify which profile in the controller. i.e.

@profile = Profile.first

or if the cause model belongs to the profile model:

@profile = Profile.find(params[:profile_id])


Related Topics



Leave a reply



Submit