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 controllerclass 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.
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
Implementing a Lookup Table in Rails
Dbi::Interfaceerror: Could Not Load Driver (Uninitialized Constant MySQL error)
Rails on Netbeans: Uncaught Exception: No Such File to Load - Script/Server or Script/Console
Question on Ruby Collect Method
Using Cucumber with Modular Sinatra Apps
Starting with Redmine Locally - How Easy Is Migration to Server Later
Error Generating Source Map - Grunt and SASS Configuration
How to Find Out What Is Intercepting 'Method_Missing'
Watir Changing Mozilla Firefox Preferences
Functional Testing of a Restful Post in Ruby on Rails
I Am Getting This Gem Install Error for Kgio Gem When I Do a Bundle Install
Capistrano, Firewalls and Tunnel
How to Include Actionmailer Class in Rake Task
Ruby Datamapper Table Inheritance with Associations
Using Elasticsearch to Filter Through Tags with Whitespace