Uploaders
File uploads are handled by Shrine, with Uppy on the front-end:
ImageUploader— base image uploaderRecordImageUploader— 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):
| Environment | Storage |
|---|---|
| production | S3 (via the S3_* ENV variables) |
| development | local filesystem (public/uploads/) |
| test | in-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:
class RecordImageUploader < ImageUploader
plugin :activerecord
plugin Trek::SavedAttachmentsReload
endShrine 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:
DRY_RUN=1 bin/rails trek:attachments:promote_cached # only lists them
bin/rails trek:attachments:promote_cachedEach 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.