Skip to content

How to: prevent carrierwave from locking the db row of your object while it's processing the image attached to that object

Francisco Quintero edited this page Nov 22, 2016 · 2 revisions

In the normal CarrierWave setup, image processing kicks off when you .save! the ActiveRecord object. Because of this a SQL transaction stays open the entire time the image is processing. Image processing can take awhile, especially if you have multiple image formats, are downloading & uploading from S3, etc. If your application wants to make any updates to the object's DB row while it's image attachment is being processed you need to change the way you cannot use this ActiveRecord post-save! hook.

This is the standard way to process remote images:

def process!( url )
  self.remote_file_url = url
  save!
end

You can re-work it like this to avoid the transaction lock:

user.pending_process_url = 'http://...'

class User < ActiveRecord::Base
  mount_uploader :pic, FileUploader
  ...

  def process!
    return if pending_process_url.nil?
  
    f = FileUploader.new
    f.download!( pending_process_url ) # from s3 > /tmp
    f.store!

    self['pic'] = CGI.unescape( pending_process_url ).split('/').last
    self.pending_process_url = nil
    save!
  end
end

As an extra bonus, if you are downloading & uploading images from S3 (for example, if you use plupload as your uploader) then you can save re-uploading the master image back to S3 since it's already there.

user.pending_process_url = 'http://...'

class User < ActiveRecord::Base
  mount_uploader :pic, FileUploader
  ...

  def process!
    return if pending_process_url.nil?
  
    f = FileUploader.new
    f.download!( pending_process_url ) # from s3 > /tmp
    f.versions.values.each do |uploader|
      uploader.store! # resize & upload to s3
    end

    self['pic'] = CGI.unescape( pending_process_url ).split('/').last
    self.pending_process_url = nil
    save!
  end
end
Clone this wiki locally