Skip to content

Uploaders ​

File uploads are handled by Shrine, with Uppy on the front-end:

  • ImageUploader — base image uploader
  • RecordImageUploader — attach an image to any record: include RecordImageUploader::Attachment(:image)
  • ModelImageUploader — model-level image uploader (used by content editor images)

Storage ​

Configured per environment in the generated Shrine initializer (config/initializers/shrine.rb):

EnvironmentStorage
productionS3 (via the S3_* ENV variables)
developmentlocal filesystem (public/uploads/)
testin-memory

Image processing uses libvips, blurhash placeholders are generated for progressive loading, and direct uploads go through the Shrine upload_endpoint (20 MB max).

Attachments and records reloaded mid-save ​

RecordImageUploader loads Trek::SavedAttachmentsReload on top of Shrine's activerecord plugin:

ruby
class RecordImageUploader < ImageUploader
  plugin :activerecord
  plugin Trek::SavedAttachmentsReload
end

Shrine resets every attacher when a record is reloaded, which is right for an explicit reload but loses a pending attachment when something reloads the record during the save — closure_tree does exactly that in its after_save callback when it reorders the siblings of a numerically ordered tree, as the generated Page is. The file would then never be promoted out of the cache storage. The plugin keeps, across such a reload, the attachers whose file was saved with the record; an attachment assigned but not saved is still discarded.

Files left in the cache storage ​

An uploaded file first lands in the temporary cache storage, and is promoted to the permanent store after the record is committed. A record whose promotion was skipped keeps pointing to the cache, and its file breaks as soon as the cache is cleaned up. To find those records, for every model and attachment, and promote the ones whose file still exists:

bash
DRY_RUN=1 bin/rails trek:attachments:promote_cached # only lists them
bin/rails trek:attachments:promote_cached

Each line gives the status (promoted, promotable on a dry run, missing when the cached file is gone, changed when the record changed meanwhile), the record and attachment, and the file id. Missing files have to be uploaded again.

Released under the MIT License.