Blog

protecting paperclip downloads

protecting paperclip downloads

This tutorial is about the gem Paperclip. But it is not about the basics. For introductions about this you have to google. There are a lot of blogposts about that already in the internet.

Following explanations demonstrate how you could protect documents, which are uploaded via Paperclip. Further this documents are additonal protected through an authorization process and through an extra password for each document. You can use Devise, Authlogic, or other systems you prefer for your authorization process.

Logged in admins are allowed to read the documents without password input, logged in customers must authenticate with passwords.

So let's start: First you have to add a new model. I call it "document". This model just contains standard Paperclip stuff with a few overriedes. Further it has the attribute "password".

I override the default save path. Instead of my public directory, I save the documents in a directory called "documents". This directory gets created at my applicaton's root level. So nowbody could read this data from outside.

Furhter I add an :url path. This is necessary for the download method, which will be explained later.

app/models/document.rb

class Document < ActiveRecord::Base

  # validations
  validates :password, :presence => true
  
  # post_process just if document is an image
  before_post_process :is_image?

  def is_image?
    ['image/jpeg', 'image/pjpeg', 'image/png', 'image/x-png', 'image/gif'].include?(self.document_content_type)
  end

  has_attached_file :document
    :path => ':rails_root/documents/:class/:id/:style/:basename.:extension'
    :url => '/documents/:id/download'
end

Next you have to modify your controller:

app/controllers/documents_controller.rb

class DocumentsController < ApplicationController
  before_filter :your_auth_system_admin, :only => [:show]
  before_filter :your_auth_system_admin_or_customer, :only => [:index, :download]

  def index
    @documents = Documents.all		
  end

  def download
    @download = Download.find(params[:id])
    password = params[:password] 
    if @document.password == password # here you can add an encryption and decryption for your password field (md5, sha1, etc.)
      send_file @document.document.path, :type => @document.document_content_type, :disposition => 'inline' 
    else
      flash[:error] = "Wrong password, access denied"
      redirect_to documents_path
    end
  end

  def show
    @document = Document.find(params[:id])
    send_file @document.document.path, :type => @document.document_content_type, :disposition => 'inline' 
  end

end

Now let's have a look at the view. You just need the documents#index view:

app/views/documents/index.html.erb:

<% @documents.each do |document| %>
  <%= document.document_content_name %>
  <%= form_tag download_url(:id => document.id) do %>
    <%= label_tag :password, "Password" %>
    <%= password_field_tag :document, document.id %>
    <%= submit_tag "DOWNLOAD" %>
  <% end %>
<% end %>

And last, but not least you have to modify your routes.

config/routes.rb:

resources :documents
match 'documents/:id/download' => 'documents#download', :as => :download

And thats it. Now you have the possibility to upload documents, give them passwords and protect them from outside access. You can give your customers passwords for the documents and they can download them. As admin you must just be logged in and you have access to everything. The extra password protection could be to much, but if you just have one customer account and a lot of customers, you could specify the access for each customer in an extra way.

22.05.2011
Matthias Frick
Ruby on Rails
1 Kommentar

Über den Autor

Matthias Frick
Matthias Frick, MSc.

Er ist ein langjähriger Ruby-on-Rails Entwickler und leitet das Unternehmen Frick-Web.

1 Kommentar zu "protecting paperclip downloads"

  1. JK139
    JK139 09.08.2011
    Nice blogpost! Very usefull!

Kommentar verfassen