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.