WIP: Add file uploads with configurable storage#2016
WIP: Add file uploads with configurable storage#2016wout wants to merge 16 commits intoluckyframework:mainfrom
Conversation
This commit adds the attachment module with some convenience methods and basic setup, storage with memory and file store classes, and an uploader base class.
Makes sure `Lucky::UploadedFile` can be considered as an IO-ish object in uploader.
Tests the integration between Lucky::UploadedFile and Lucky::Attachment::Uploader
This feature makes it possible to configure dynamic path prefixes globally or per attachment. For example: ":model/:id/:attachment", which would then resolbve to somethign like "user_profile/123/avatar".
|
I just had a quick look through this, and it looks awesome.
My first thought was probably inside Avram, and maybe within the Lucky extension if needed. Params sort of works that way. Now for my questions: Does this mean that the Yeah, this all looks pretty good. 🚀 |
|
Yeah, I think having it in Avram would make it easier to test, I still have to write those for that part. I suppose we can create mock objects for the Lucky parts or something. It will probably be easier to write tests for it in the Avram repo than in the Lucky repo. As for your question: no the I think it's also good to keep UPDATE attribute {{ field_name }} : Avram::Uploadable |
Purpose
This is the first part of the
Lucky::Attachmentimplementation (#1995). Test pass and it works inside the app I'm building, but it's not yet the complete first version of what I intend to create for the first phase. My goal is to have this ready by the end of next weekend.Description
It's quite a lot of code already, so I want to put it out here for everyone to see and comment. I'll chop the description up in sections for easier reading.
Setting up models and operations
This is something I immediately have a question about. There are three modules for Avram:
Avram::Attachment::ModelAvram::Attachment::SaveOperationAvram::Attachment::DeleteOperationBy including the
Avram::Attachment::Modelin a model, the other two get included in the operations automatically. This could be either included by default, or manually if the user decides to use attachments in models.My question is: where does this code live? It depends on the
Lucky::AttachmentHabitat configuration and some classes as well, so it can't be used without Lucky. Should it live in the lucky repo and be renamed? Or should it live in the Avram repo?Setting up an attachment
Note
The underling column here is nilable, but it can also not be.
The in the operation:
Important
There's no type declaration here, just the reference to the column in the model. If it does not exist on the model, there will be a compile-time error.
This will set up a
file_attributecalledavatar_filewhich can be used in the forms. If the value is nilable, there will also be adelete_avatarattribute which takes a boolean.Setting up the uploader
Here users can override a number of methods to customize behaviour. This is also where variants and other features will be configured.
Setting up the stores
Currently I only implemented
memoryandfile_system, but next weekend I'll adds3and compatible.Rendering attachments
In a form, so you always get a fresh version:
file_input op.avatar_file if avatar = op.avatar.value img src: avatar.url checkbox op.delete_avatar endElsewhere:
The flow
Attachments are uploaded to the cache first in a
before_savecallback. When validation passes, the file is moved from the cache to the store in anafter_commitcallback.If validation fails, the user does not have to select the file again. The reference to the cache will be re-submitted and the file can be rendered because it is already in the cache store.
If a record with attachments is deleted, the delete operation will automatically trigger deletion of the files in a
after_deleteblock. So there's no manual configuration required to clean up any files still in the store.What does have to be managed though, are any files remaining in the cache storage. If a user submits, validation fails, and then the user closes the browser, the file will be in the cache forever. This is also the case with Shrine.rb in Ruby apps. We just set a retention period of 30 days for the cache dir on our MinIO instances.
What's next?
Lucky::Attachment::Storage::S3Checklist
crystal tool format spec src./script/setup./script/test