Search code examples
ruby-on-railsrails-activestorage

ActiveStorage image blob disappears


In Rails 5.2.1, I have ActiveStorage (5.2.1) configured for the Disk service.

I have a Pic model:

class Pic < ApplicationRecord
  has_one_attached :image
end

I can attach images:

imgpath = "/tmp/images/..."
Pic.first.image.attach(io: File.open(imgpath), filename: imgpath)

I wanted to do this in something like a Rake task (but the result is the same if done from the Rails console) to batch-upload images, like for example:

pfs = Dir['testpics/*']
Pic.all.each { |pic|
  pf = pfs.shift
  pic.image.attach(io: File.open(pf), filename: pf)
}

This runs without errors. However, quiet surprisingly (to me at least) some images don't have a corresponding blob afterwards, and queries fail with 500 Internal Server Error: Errno::ENOENT (No such file or directory @ rb_sysopen.

Checking pic.image.attached? returns true. However, pic.image.download throws an exception.

Even stranger, calling pic.image.download right after attaching it does work. 2 seconds later it doesn't.

The only way I could come up with to tell if an image uploaded correctly is to wait ~2 seconds after attaching it, and then try to download. If I keep retrying the attach after waiting 2 seconds and checking if it's ok, all images will be ok. But obviously this is not the right thing to do. :) Simply waiting between attach calls does not help, I have to check after the wait, then reattach and then check again until it is ok - sometimes ok on the first try, sometimes 10th, but eventually it will succeed.

This is all on my local disk, not for example ephemeral storage in Heroku. Also I'm running it on Ubuntu 18.04 (Bionic), with nothing installed that should remove blobs (ie. no antivirus or similar). I really think the problem is internal to ActiveStorage, or the way I use it maybe.

What's going on? Where do blobs go after a few seconds, when they were already uploaded succesfully?

With the S3 service everything is fine, blobs don't disappear.


Solution

  • Wow I think I figured this out. This is not so much of an ActiveStorage issue, but I will leave the question here in case it might be useful for somebody else too.

    It turns out the problem was likely Dropbox. :)

    What happens is with the Disk strategy, ActiveStorage stores identifiers of two characters in the storage/ directory - similar to a hash. These can (and quite often do) happen to only differ in case, like for example there is a zu and a Zu directory. The way the Dropbox client interferes with this is that if all of this is in a directory that is synced with Dropbox, these directories will get renamed, for example "Zu" will become "zu (Case Conflict)" (so that Dropbox sync works across platforms).

    Of course the blobs are not found anymore, and this all happens async, the Dropbox client needs some time to rename stuff, that's why it works for a while right after attaching an image.

    So lesson learnt, ActiveStorage doesn't work well with Dropbox.