Use token instead of id in paperclip’s path

Posted on Dec 17, 2010

I have been using paperclip in more then a couple of applications that I’m developing now, I really like it and it gives me the flexibility that I require.

Url with Token example

A couple of days ago, I wanted the path of the file to include a token instead of the id of  a user class.

This was my code before the change:

    
has\_attached\_file :avatar,
      
:styles =>
      
{
        
:tiny => "48×48>",
        
:preview => "175×175>",
        
:large => "300×300>",
        
:huge => "500×500>"
      
},
      
:storage => :s3,
      
:s3\_credentials => "#{RAILS\_ROOT}/config/s3.yml",
      
:path => ":class/:attachment/:id/:style.:extension",
      
:bucket => ‘lopsum’,
      
:default_url => "/images/photo01.jpg"
  

Notice that the path parameter includes the id of the user, this was not the requirement, because if this in an id parameter then the URL’s will be very easy to resolve and I of course don’t want that for user privacy.

I don’t want anyone to change the URL and get to the other profile images easily.

So, I needed a token which will be a random string for each user and I wanted that to be included in the path. This way, no one can tell the other paths in the system (it’s harder, a lot harder).

So, first thing first, I added this code to the user model:

    
validates\_presence\_of :token

protected
      
def before\_validation\_on_create
        
self.token = rand(36**10).to\_s(36).upcase if self.new\_record? and self.token.nil?
      
end
  

I used a random code, you can of course use MD5 of the date or whatever you may want, just replace this code:

  
rand(36**10).to_s(36).upcase
  

Now that I have a token saved in the database I changed the image saving code to this:

    
has\_attached\_file :avatar,
      
:styles =>
      
{
        
:tiny => "48×48>",
        
:preview => "175×175>",
        
:large => "300×300>",
        
:huge => "500×500>"
      
},
      
:storage => :s3,
      
:s3\_credentials => "#{RAILS\_ROOT}/config/s3.yml",
      
:path => ":class/:attachment/:token/:style.:extension",
      
:bucket => ‘lopsum’,
      
:default_url => "/images/photo01.jpg"
  

This code did not work, the path only included the word :token but without the actual token from the database.

So, how can you fix this?

You need to add an initializer for paperclip.

You add a file called paperclip.rb into the config/initializers folder

You paste in this code:

  
Paperclip.interpolates :token do |attachment, style|
    
attachment.instance.token
  
end
  

This will “tokenize” your user avatar path.