This blog is part of our Rails 6 series. Rails 6.0 was recently released.

Rails 6 adds ActiveStorage::Blob#open which downloads a blob to a tempfile on disk and yields the tempfile.

>> blob = ActiveStorage::Blob.first
=> <ActiveStorage::Blob id: 1, key: "6qXeoibkvohP4VJiU4ytaEkH", filename: "Screenshot 2019-08-26 at 10.24.40 AM.png", ..., created_at: "2019-08-26 09:57:30">

>> blob.open do |tempfile|
>>   puts tempfile.path  #do some processing
>> end
# Output: /var/folders/67/3n96myxs1rn5q_c47z7dthj80000gn/T/ActiveStorage-1-20190826-73742-mve41j.png

Processing a blob

Let’s take an example of a face detection application where the user images are uploaded. Let’s assume that the images are uploaded on S3.

Before Rails 6, we will have to download the image in system’s memory, process it with an image processing program and then send the processed image back to the S3 bucket.

The overhead

If the processing operation is successful, the original file can be deleted from the system. We need to take care of a lot of uncertain events from the download phase till the phase when the processed image is created.

ActiveStorage::Blob#open to the rescue

ActiveStorage::Blob#open, abstracts away all this complications and gives us a tempfile which is closed and unlinked once the block is executed.

 1. open takes care of handling all the fanfare of getting a blob object to a tempfile.  2. open takes care of the tempfile cleanup after the block.

>> blob = ActiveStorage::Blob.first
>> blob.open do |tempfile|
>>   tempfile  #do some processing
>> end
   # once the given block is executed
   # the tempfile is closed and unlinked

=> #<Tempfile: (closed)> 

By default, tempfiles are created in Dir.tmpdir directory, but ActiveStorage::Blob#open also takes an optional argument tmpdir to set a custom directory for storing the tempfiles.

>> Dir.tmpdir
=> "/var/folders/67/3n96myxs1rn5q_c47z7dthj80000gn/T"

>> blob = ActiveStorage::Blob.first
>> blob.open(tmpdir: "/desired/path/to/save") do |tempfile|
>>   puts tempfile.path  #do some processing
>> end

Here is the relevant commit.