Securely Display an Image Uploaded with Paperclip Gem

Securely Display an Image Uploaded with paperclip gem

You could use send_file. Assuming you have secure_image action in your routes:

resources :posts do
member do
get :secure_image
end
end

and following method in corresponding controller:

def secure_image
send_file Post.find(params[:id]).some_image.path
end

you can use protected images in your views:

<%= image_tag secure_image_post_path(@post) %>

What's happening here: usually Rails (or nginx or apache) sends static files directly bypassing security checks in sake of speed. But request for secure_image action goes through whole Rails' stack, so it is protected with your authentication system.

Display PDF's uploaded with paperclip

You have an syntax "issue":

<iframe src="<% @document.file %>"></iframe>

Should be

<iframe src="<%= @document.file %>"></iframe>
<!-- notice the equals symbol (=) -->
<!-- which prints something into erb file. -->

Also, I believe you need to use it's url, so I'd be something like this:

<iframe src="<%= @document.file.url(:large) %>"></iframe>

More info - What is the difference between <%, <%=, <%# and -%> in ERB in Rails?

Authorizing Access to Attachments (using paperclip gem)

You have 2 choices:

First choice is to store the uploaded files in a non-public directory, and provide a controller action to authenticate the user and let her download the file. You can use any authentication library. As for the download part, just use the helper method send_file

the model class

class MyModel < ActiveRecord::Base
has_attached_file :image, :path => '/non-public/dir/:attachment/:id/:style/:basename.:extension',
:url => '/downloads/:id'
end

the controller

class DownloadsController
def show
# Authenticate user
model = MyModel.find(params[:id])
send_file model.image.path
end
end

The second choice is simple, keep the file in the public directory, but give it a random path which is hard to guess. And you also have to provide a controller action to authenticate users, but this time, instead of sending files to the users, you just redirect them to the file URL.

Pros and Cons

The first choice is very safe, but it requires your rails application to handle the file download. If you're using a threaded or preforked server, this could be a penalty to concurrency.

The second choice is less safer, but you can rely on your HTTP server (e.g. Nginx) to handle the file download, while rails application only do the authentication. It's much faster.

How show hide image in paperclip when no image present

I use the following to find wether a model has an associated attachment:

<% if @agent.avatar.file? %>
<%= image_tag @agent.avatar.url(:normal) %>
<% else %>
No attachment available!
<% end %>

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 and Paperclip, use a different image, not an uploaded one to be processed

Here's a method to use a RemoteFile instead of an uploaded file... Check out the blog post for how to create a RemoteFile, which is a subclass of TempFile

#console
remote_file = RemoteFile.new("http://www.google.com/intl/en_ALL/images/logo.gif")
remote_file.original_filename #=> logo.gif
remote_file.content_type #= image/gif

#controller
def import
#...snip
@imported_user.images.create(:file => RemoteFile.new( url_to_image ))
#...snip
end

http://coryodaniel.com/index.php/2010/03/05/attaching-local-or-remote-files-to-paperclip-and-milton-models-in-rails-mocking-content_type-and-original_filename-in-a-tempfile/



Related Topics



Leave a reply



Submit