You know on some sites when you're asked to upload, say, an avatar, you click on the button, select your file, then hit OK, but before you Submit the page (as in, no record is created/updated), a little preview of the image shows up?
How would I accomplish this using Paperclip for Rails?
Bonus points for anyone who can point me towards a tutorial or something that might tell me how to do a Javascript crop on the image before saving the record.
I haven't been able to find much on Google on the subject... thanks for the help!
Paperclip is an easy file attachment library for Rails Applications. Attached files are saved to the file system, database or cloud and referenced in the browser by an easily understandable specification.
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:
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.
I found the solution posted here useful, you just need to modify it to be only one file (if you are doing single file upload):
<%= image_tag @upload.image, id:"something_unique"%>
<div class="row">
<%= form_for @upload, :html => { :multipart => true } do |f| %>
<%= f.file_field :image, id:"something_else_unique" %>
<%= f.submit "Add photo" %>
<% end %>
</div>
<script>
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
f=files[0]
// Only process image files.
if (f.type.match('image.*')) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
// alert(e.target.result);
document.getElementById("something_unique").src=e.target.result;
};
})(f);
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
document.getElementById('something_else_unique').addEventListener('change', handleFileSelect, false);
</script>
Note: I used a separate model for paperclip, an upload model that has the image attribute. You can add styling to the image preview tag to format the picture size (otherwise it will be the original size).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With