Development

Rename S3 assets after paperclip hashing


I just found out about paperclip hashing to keep your styles as a ‘not easy to guess’ url so something like this:

products/1/original/image.jpg

becomes something like this

products/1/sadGFASgoaw4eaw40q2asfq23/image.jpg

this way is harder for people to guess your styles, which might be private some how.

This is really simple to set up all you need to do is set up a hash_secret default option for paperclip and add :hash in the asset path in an initializer, like this:

Paperclip::Attachment.default_options.update({
  :path => ":class/:attachment/:hash/:style.:extension",
  :hash_secret => ENV[RANDOM_SECRET]
})

And voila, now you have complex to guess urls for your assets, but, when you go and check the site you’ll notice that all the images point to non existing files so we need to copy/move/rename all the old files to the new S3 url.

I spent some time finding how to generate the :hash param in the url so I can copy files from the old url into the new one, and I found a method in paperclip attachment model called hash_key, this method receives the syle name and does a Digest interpolating your unique hash_secret and the style name.

So now that we know how to generate the proper url to copy to, we need to actually copy the files, so I came up with this small rake task that uses amazon AWS SDK to copy all files to the new location.

namespace :aws do
  namespace :rename do
    task media: :environment do
      Model.all.each do |m|
        [:original, :medium, :thumb].each do |style|
          s3 = AWS::S3.new
          key = "model/#{m.id}/#{style}/#{m.attachment_file_name}"
          object = s3.buckets[:bucket_name].objects[key]
          next unless object.exists?
          hash = m.attachment.hash_key style
          copy_key = "m/#{m.id}/#{hash}/#{m.attachment_file_name}"
          puts "Copying to #{copy_key}"
          object.copy_to(copy_key, acl: :public_read)
        end
      end
    end
  end
end

Please be carefull with the key and copy_key variables I’m using in this snippet since they’re different in each project depending on your path configuration, also, notice how im using acl: :public_read in the copy_to method since those styles being copied are meant for public access and paperclip by default makes them public but copying them using AWS doesn’t so make sure you want those assets either public or private and set the necessary permissions to them.

Note: You can also use move_to method instead of copy_to, but I wouldn’t recommend it because something could go wrong and this way you’ll have some sort of backup.

Agile
React JS: Communication between components
Development
Getting your eCommerce ready for the following holidays
Android
How to build Android apps and not crash in the attempt (Part I)