I have a Feature where user uploads an XML file and the system should read the file and import data. So the file is not attached to any Model Record. So I have a form which allows file input
<%= form_with(
multipart: true,
scope: :ctf,
url:some_path,
id: dom_id(Import.new, :form),
data: { turbo: false }
) do |form| %>
<%= render Content::SectionComponent.new do |section| %>
<span class="text-sm"><%= 'Upload XML' %></span>
<%= form.label :cf_file, 'File' %>
<%= form.file_field :cf_file, accept: 'application/xml', required: true %>
<% end %>
<% end %>
In the controller, I get the file as param and manually upload it using ActiveStorage::Blob.
def cf_upload
importer = Import.new(cf_upload_params)
if importer.valid?
file_storage = ActiveStorage::Blob.create_and_upload!(io: cf_upload_params[:cf_file], filename: filename)
Importers::Cf::ImportJob.perform_later(file_storage)
else
flash.now[:alert] = 'Something went wrong'
end
render :index
end
Is there any way I can use ActiveStorage direct_upload for this instead of doing upload using ActiveStorage::Blob.create_and_upload?
According to the docs ActiveStorage::Blob
is a database record, and it has been designed with ActiveRecord models in mind.
One possibly viable option for you would be to use Direct Uploads which essentially allows you to set up some JS so the file is uploaded directly to your storage service (e.g. S3) and what your form submits is a token, or the identifier of the uploaded file.
But this solution is also built on the assumption the ActiveStorage::Blob
is created. So probably you'd need to hack your way around it.
But if you're asking - can you create the blob and upload it to the service without attaching it to any other model - absolutely. Unatached blobs are a thing, which is why the docs are explaining how to purge them if you want to clean up house.