Search code examples
ruby-on-railsrails-activestorage

How can I verify that an ActiveStorage blob is actually present?


I've got an application that's been running in production for many months now, with tens of thousands of attachments. This morning, I tried to do an operation on one of these attachments, and got the following error:

Azure::Core::Http::HTTPError: BlobNotFound (404): The specified blob does not exist.

I can easily recreate this blob, but this situation makes me want to write a script to check the integrity of all of my attachments, and verify that no others have gone missing. (I expect that this was a transitory network error, and I expect to find very few, but I need the peace of mind.)

I can see that there is a method to call that seems to do exactly what I need: exist?(key), which is documented here:

https://github.com/rails/rails/blob/master/activestorage/lib/active_storage/service/disk_service.rb

However, I can't figure out how I'm supposed to call it. According to this, it's implemented as an instance method. So how do I reference my Rails application's active ActiveStorage instance (depending on environment) to use this method?


Solution

  • I wondered if it were possible to backtrack to get the instance of ActiveStorage::Service::AzureStorageService (in production), and found this answer on finding each instance of a class.

    From there, I found that I could:

    asass = ObjectSpace.each_object(ActiveStorage::Service::AzureStorageService).first
    

    Which then allowed me to:

    2.5.5 :015 > asass.exist?(c.json.blob.key)
      AzureStorage Storage (313.3ms) Checked if file exists at key: ....PTLWNbEFLgeB8Y5x.... (yes)
     => true
    

    Further digging around in the bowels of Rails' GitHub issues led me to see that the reference to the ActiveStorage service instance can be reached through an instance of a stored object, and that I could always be using the send() method to call one of its methods:

    2.5.5 :045 > c.json.blob.service.send(:exist?, c.json.blob.key)
      AzureStorage Storage (372.4ms) Checked if file exists at key: ....PTLWNbEFLgeB8Y5x.... (yes)
        => true
    

    I'm sure both approaches are lighting up the same code paths, but I'm not sure which one I prefer at the moment. I still think there must exist some way to traverse the Rails instance through app. or Rails.application. to get to the ActiveStorage instance, but I haven't been able to suss that out.