Rails Active Storage: how to access file contents before it has been saved

I am working on building an API front end for a 3rd Party API. In addition to collecting the file from my user, I also need to post the file to the 3rd Party Service.

The only way I have been able to get the actual file contents is to download it again after it has been saved.

class Template < ApplicationRecord
has_one_attached :pv_file

post_body << self.pv_file.blob.download

``

I want to have a before create filter that throws an error if the 3rd Party API rejects the file (e.g. wrong format, service unavailable, etc), but the only way I have found to access the file content is by downloading it again.

How can we access the actual file content before it has been saved and uploaded?

Hi Nerdture,

I’m not a core team member, but I believe that there’s currently no documented way of accessing a file before the record has been saved (more precisely, before the after_commit callback). There is, however, attachment_changes hash, which keeps track of what changes are made. You should be able to access the attachment with record.attachment_changes['pv_file']. Keep in mind that this is undocumented internal api, so it could change in the future.

Thanks Mladen Ilic for your reply.

I think I am getting closer to the solution I need.

You should be able to access the attachment with record.attachment_changes['pv_file'].

I must be doing something wrong, as I can’t figure out how to access the actual file contents/octet-stream.

post_body << self.attachment_changes[‘pv_file’]

``

throws Zlib::Data Error incorrect header check

post_body << self.attachment_changes[‘pv_file’].blob.download

``

throws Aws::S3::Errors::NoSuchKey

post_body << self.attachment_changes[‘pv_file’].blob.open

``

throws ActiveStorage::FileNotFoundError

I am sure I am showing my Ruby ignorance here.

Any help is appriciated.

Hi again Nerdture,

According to the implementation of ActiveStorage::Attached::Changes::CreateOne, you should be able to access instance of* ActionDispatch::Http::UploadedFile* with following:

self.attachment_changes[‘pv_file’].attachable

``

In you examples, you are trying to download file from a storage service to a tempfile before it has been uploaded, so storage service fails to locate it.

Best,

Thanks again Mladen Ilic for your help.

For anyone that finds this, in order to build the multipart form-data, I needed to use the following to get the Octet-stream.

post_body << self.attachment_changes[‘pv_file’].attachable.read

``

Hopefully we will eventually get a permanent/documented way to access the data pre-save.