Accessing ActiveStorage Blobs Inside Transactions
TLDR: You can't.
I spent way too much time trying to debug an issue with ActiveStorage where files that I create and store with ActiveStorage are unavailable when I call download
What Iām doing is creating a file in memory, attaching it to a model with ActiveStorage and then writing it to disk. Iām using download
to get the file from ActiveStorage. Thereās a lot of other stuff going on in this process so everything is wrapped in transactions. This doesnāt work. The file contents arenāt available in ActiveStorage until the transaction has ended.
There are several issues on Github about this behaviour but none of them have been resolved with anything satisfactory. Eg
And there is this Stack Overflow post that confirms the same behaviour.
Why do I get ActiveStorage::FileNotFoundError
when trying to seed the db with attachments?
The easiest way for me to replicate the problem is by seeding the database.
I have come up with three possible solutions
- Write the file data to disk from memory rather than plucking it from active storage. I have the file data so I can write it immediately and then store it.
- Trigger the file writing via a background job. Where I used to call the attachee to write the file, I make the same call in a background job with
perform_later
- A variation of this is to set a āwaiting to writeā state on the file and have a job that periodically checks for files in that state and processes them.
Option 1 seems like the obvious choice. I have the file data so just write it straight away, but in the long term I think I will want to concatenate several files together before sending them to a third party which means option 3. In the short term though Iām going to pick option 2. Gives me fairly immediate file sending and sets up the job infrastructure for later.