Paperclip, S3 & Delayed Job in Rails

Here’s how I use Paperclip (with storage on S3) and delayed_job to process images after they’re uploaded in the background. This means users don’t have to wait while the images are resized to the versions you’ve specified in Paperclip’s :style option.

Assumes you have Paperclip configured using S3 for an existing model (Image in this example) and delayed_job installed (as plugin or gem) with the required table created.

Add a :processing flag to our model:

class AddProcessingToImages < ActiveRecord::Migration
  def self.up
    add_column :images, :processing, :boolean
  end
 
  def self.down
    remove_column :images, :processing
  end
end

Then, in our model:

class Image
 
  # define our paperclip attachment
  has_attached_file :source ...
    
  ...
  
  # cancel post-processing now, and set flag...
  before_source_post_process do |image|
    if image.source_changed?
      image.processing = true
      false # halts processing
    end
  end
 
  # ...and perform after save in background
  after_save do |image| 
    if image.source_changed?
      Delayed::Job.enqueue ImageJob.new(image.id)
    end
  end
 
  # generate styles (downloads original first)
  def regenerate_styles!
    self.source.reprocess! 
    self.processing = false   
    self.save(false)
  end
 
  # detect if our source file has changed
  def source_changed?
    self.source_file_size_changed? || 
    self.source_file_name_changed? ||
    self.source_content_type_changed? || 
    self.source_updated_at_changed?
  end
  
  ...
  
end

Create a job wrapper, which used by DelayedJob:

class ImageJob < Struct.new(:image_id)
  def perform
    Image.find(self.image_id).regenerate_styles!
  end
end

Thanks to this article which helped a lot.

A mix of code and design by Mark Dodwell, developer and designer.