Changing styles with Paperclip

Posted on Feb 12, 2013

Just a quick Ruby tip today. If you use the Paperclip gem for image attachment with Ruby, you might have noticed the option to use a hash as part of your URL. Using this provides a simple way of creating a secret URL for your images. Rather than an easily predictable URL, a section of the URL created by hashing a secret key with a row from the database. For instance, the following code you might get a URL like /avatars/square/c2794196caf44b11b0b7b70cfd12ab88.png.

class User < ActiveRecord::Base

  has_attached_file :profile_pic,
    :styles => { :biography => "720x600>", :square => "100x100#" },
    :url => "/avatars/:style/:hash.:extension",
    :hash_secret => "This Is My Very Secretive Key."

end

The issue is that styles tend to change over time. Where you need a 150x150 image today, you might need 125x125 tomorrow. According to the documentation, after modifying the style you have to reprocess all of the images in order for the new style to take effect. Normally this would just be a matter of running an included rake task to regenerate all of the images:

rake paperclip:refresh CLASS=User

This time, however, things are a bit more difficult. Though the documentation describes the above procedure, it doesn't work properly if the URL uses a hash. The cause is that the fields on the image are modified when the image is reprocessed and are then used to generate the hash. This wouldn't be a problem if it weren't for the fact that the rake task doesn't actually call save on any of the objects after reprocessing them. Since the row is now unchanged again, the newly used hash is no longer valid for the object. This creates a situation where the filenames are updated but the references are not.

With this in mind, it becomes a simple matter to regenerate all of the images: after reprocessing an image, all we have to do is save the row to the database. This should make future hash generations use the same input as the row that we just generated. Thus, the issue can be avoided if we replace our rake task with a bit of code only slightly greater in length.

User.each do |user|
  user.profile_pic.reprocess!
  user.save
end

After reprocessing the photo, persist the changes to the database. With this, you can safely change styles as much as you like.