Last active
November 24, 2021 15:57
-
-
Save thedanbob/38454f9d5d1a413b0c8bb4fc3dcc077f to your computer and use it in GitHub Desktop.
Integrating Dropzone with ActiveStorage direct uploads
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<%= form_for @album, multipart: true do |f| %> | |
<div id="dz-container" class="dropzone"> | |
<% @album.photos.includes(:blob).each do |photo| %> | |
<%= render 'preview', blob: photo, field: 'album[photos]' %> | |
<% end %> | |
<div class="fallback"> | |
<%= f.file_field :photos, multiple: true, direct_upload: true %> | |
</div> | |
</div> | |
<%= f.submit 'Save' %> | |
<% end %> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<div class="dz-preview dz-image-preview"> | |
<div class="dz-image"><%= image_tag(blob.representation(resize_to_fill: [120, 120])) %></div> | |
<div class="dz-details"> | |
<div class="dz-size"><span><%= number_to_human_size(blob.byte_size) %></span></div> | |
<div class="dz-filename"><span><%= blob.filename %></span></div> | |
</div> | |
<a class="dz-remove remove-existing" href="#">Remove file</a> | |
<%= hidden_field_tag "#{field}[]", blob.signed_id %> | |
</div> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Dropzone from 'dropzone' // dropzone@5.9.3 | |
import { BlobRecord } from '@rails/activestorage/src/blob_record' // @rails/activestorage@6.1.4 | |
import { FileChecksum } from '@rails/activestorage/src/file_checksum' | |
Dropzone.autoDiscover = false | |
document.addEventListener('DOMContentLoaded', function() { | |
let dz = document.querySelector('#dz-container') | |
if (dz) { | |
const fileInput = dz.querySelector('input[type="file"]') | |
let dropzone = new Dropzone(dz, { | |
url: (files) => files[0].blobRecord.directUploadData.url, // Unique URL to upload file, returned in step 1 | |
method: 'put', | |
uploadMultiple: false, | |
chunking: false, | |
addRemoveLinks: true, | |
// Step 1: request an empty blob from the server | |
accept: (file, done) => { | |
if (file.size == 0) { | |
return done('File is empty (0 B).') | |
} | |
FileChecksum.create(file, (error, checksum) => { | |
if (error) { | |
return done(error) | |
} | |
const blobRecord = new BlobRecord(file, checksum, fileInput.dataset.directUploadUrl) | |
blobRecord.create(error => { | |
if (error) { | |
return done(error) | |
} else { | |
file.blobRecord = blobRecord // Store blob info in file object | |
return done() | |
} | |
}) | |
}) | |
} | |
}) | |
// Step 2: add extra headers that ActiveStorage expects | |
dropzone.on('sending', (file, xhr) => { | |
xhr.responseType = 'text' | |
const { headers } = file.blobRecord.directUploadData | |
for (const key in headers) { | |
xhr.setRequestHeader(key, headers[key]) | |
} | |
}) | |
// Step 3: override submit method to send just file, not FormData | |
dropzone.origSubmitRequest = dropzone.submitRequest | |
dropzone.submitRequest = function(xhr, formData, files) { | |
dropzone.origSubmitRequest(xhr, files[0].slice()) | |
} | |
// Step 4: add blob's signed_id to form | |
dropzone.on('success', (file) => { | |
const hiddenField = document.createElement('input') | |
hiddenField.type = 'hidden' | |
hiddenField.name = fileInput.name | |
hiddenField.value = file.blobRecord.attributes.signed_id | |
file.previewElement.appendChild(hiddenField) // gets removed if preview element is removed | |
}) | |
// Remove existing files | |
dz.querySelectorAll('.remove-existing').forEach(el => { | |
el.addEventListener('click', e => { | |
e.preventDefault() | |
el.parentNode.remove() | |
} | |
}) | |
} | |
}) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment