Paperclip: Timestamping Attachments on Upload
It’s not my intention to make this a Paperclip-only blog, but I recently had another requirement that was quite simply accomplished, and thought it was common enough to be useful to others.
Timestamping attachments could be valuable for several reasons – in our case, it was made necessary due to our site moving to S3 and Cloudfront for the delivery of our static assets. If the content of a file changes but its name remains the same, Cloudfront’s edge nodes will happily continue serving stale content for any asset they’ve cached, which is obviously undesirable.
We therefore need to ensure that attachments have their filename
timestamped on upload. Initially I did this with a ghastly hack
involving subclassed Tempfiles with an overridden #original_filename
method, but this was, well, ghastly. I also briefly tried using
Paperclip’s built-in callbacks, but it turned out to be much nicer to do
it with a custom processor, like so:
module Paperclip class TimeStamper < Processor def initialize(file, options={}, attachment=nil) super(file,options,attachment) timestamp_filename end def timestamp_filename original_filename = attachment.instance_read(:file_name) extension = File.extname(original_filename) date_format = @attachment.options[:date_format] || "%Y%m%d%H%M%S" timestamp = DateTime.now.strftime(date_format) new_filename = "#{timestamp}-#{original_filename}" @attachment.instance_write(:file_name, new_filename) end def make @file end end end
The key bit is using the attachment’s
#instance_write method
, as suggested by Trevor
Turk
for a slightly different purpose. This sets the instance variables that
Paperclip uses to determine the uploaded filename.
Place this file somewhere in your load path (ideally
lib/paperclip_processors
), and tell your models to use it after
thumbnailing (or before, actually, it doesn’t really matter). Note that
you now have to explicitly tell Paperclip that you want to use the
Thumbnail processor.
class User < ActiveRecord::Base has_attached_file :image, :styles => { :large => "280x280#", :medium => "130x130#", :small => "50x50#", :tiny => "30x30#" }, :processors => [:thumbnail, :timestamper], :date_format => "%Y%m%d%H%M%S" end
You can specify the date format using the standard format strings, or you can omit the option and a default will be used. Now whenever an attachment is created or altered, its filename will have a date string prepended to it, and your new content will be served as intended, whatever your distribution details are.
comments powered by Disqus