11

In Rails 6 I have a form with a file field and I am using activestorage to store the file. If validations fail after submitting the form, the form is redisplayed showing the validation errors. How can I retain the file added to the file field when redisplaying the form so that the user does not have to add the file again to the form?

There is already a similar question for rails 5: Active Storage: Best practice to retain/cache uploaded file when form redisplays, however the solution there only applies to Rails 5.

Robban
  • 1,191
  • 2
  • 13
  • 25
  • You said "however the solution there only applies to Rails 5". Do you have any error? – cercxtrova Jun 18 '19 at 13:08
  • The comments in the post he linked to explains - rails 6 no longer stores the file on assignment but on save, meaning the technique used there won't have access to the required file – Mark Jun 18 '19 at 14:06
  • Oops, my bad. Maybe you should consider to use a model to save attachments before the record's validation, then attach them to the record when it's saved? – cercxtrova Jun 18 '19 at 14:18
  • 2
    Anyone have an answer for how to do this WITHOUT using `direct_upload`? I really dislike what we have to do to open up CORS to make that work. – Michael Scott Shappe May 21 '20 at 18:47

3 Answers3

7

Since Rails 6 does not store the file on assignment, the workaround I found was to enable direct upload on the file field. This will upload the file via javascript before the form submission.

= f.file_field :doc, direct_upload: true

For this to work, you also need to add activestorage.js to your bundle as described in the Active Storage guide.

After that change one can use the method described in the question Active Storage: Best practice to retain/cache uploaded file when form redisplays. That means adding the signed_id to your form in a hidden field as follows:

= f.file_field :doc, direct_upload: true
= f.hidden_field :doc, value: f.object.doc.signed_id if f.object.doc.attached?
Robban
  • 1,191
  • 2
  • 13
  • 25
  • 2
    Shouldn't the hidden field come first? https://youtu.be/mG1BUMuSmsc?t=577 – M-Dahab May 11 '20 at 01:16
  • This doesn't work when editing an item that already has an attachment. It will retain the existing attachment. – Kieran Andrews May 15 '20 at 12:14
  • Robban answer does work for me (even without the direct_upload). This article explains this answer further: https://medium.com/@TETRA2000/active-storage-how-to-retain-uploaded-files-on-form-resubmission-91b57be78d53 – lcjury Jan 05 '23 at 05:10
2

In addition to Robban answer, for multiple attachments, and doing some previewing

  = f.file_field :attachments, multiple: true, direct_upload: true
  - f.object.attachments.each do |attach|
    = f.hidden_field :attachments, value: attach.signed_id, multiple: true
    = image_tag attach.preview(resize_to_limit: [100, 100]) if attach.previewable?
    = image_tag attach.variant(resize_to_limit: [100, 100]) if attach.variable?
Ccastillop
  • 791
  • 6
  • 9
0

I found the solution to store file with form post (without direct upload). But it requires additional code to the usual scaffolded code @mention = Mention.create(mention_params)

controller code:

@mention.screenshot.blob.upload(mention_params[:screenshot])
@mention.screenshot.blob.save

while debugging check that it creates a record in active_storage_blob table.

Once file uploaded you can reuse signed_id on next submissions (when model validation does not pass).

view code:

f.hidden_field :screenshot, value: ...screenshot.signed_id if ...screenshot.attached? %>

It is not a clean solution but I think you'll get the point.

woto
  • 2,893
  • 1
  • 29
  • 24