This is awesome, i'll be implementing this instead of the action text embeds so I have more control over the layout when displaying images and other documents. thank you!
☒ Great question. Since the stimulus controller is creating a hidden element, you would need to remove that hidden element with something like this. I would console log the file to see what parameters are available and then remove the hidden element based on those parameters.
I do have a question, if i wanted to place this on an existing record and remotely update on the record how would I go about handling the array of multiple files/images? I've tacked on the below to the "addedfile" method but getting a 'unpermitted param evidences' error even though I have evidences: [] permitted in params. I think it's how i'm formatting the params in the formData.append - any clues? (I've got this working with one file)
let formData = new FormData()
formData.append("event[evidences]", this.hiddenInput.value);
Rails.ajax({
url: this.data.get("update-url"),
type: "PATCH",
data: formData
});
Thanks for the quick reply, It's actually coming through as Parameters: {"event"=>{"evidences"=>"event[evidences][]"}, "id"=>"22"} which tells me I may not need append, but removing this throws a 'event not present' error for the params.
When you drag the images on the page, did you verify that the direct upload is working? You should be able to check the console to see if Active Storage is creating the blobs. Once it creates the blob, the stimulus controller should create the hidden elements. Do an inspect on the browser to see what the elements look like. There does seem to be something off as the blob's signed_id should be getting set as the value.
Thanks for pointing me in the right direction, it was working with the direct upload, but I was passing the blob signed id to the controller as a string rather than an array, this worked below:
let formData = new FormData()
formData.append("event[evidences][]", [this.hiddenInput.value] )
Rails.ajax({
url: this.data.get("update-url"),
type: "PATCH",
data: formData
});
I could not upload the file to Digital Ocean Spaces with this dropzone_controller. It was successful with other app with same credentials and via just a normal file_field.
Ok, can you post the stimulus controller? It sounds like there is an issue with the data getting back from the direct upload. Can you also console log the blob that is getting returned from Direct Upload?
When it made the post to your direct upload endpoint, it errored out with a 422. The Rails logs may help. Have you tried testing direct upload without any stimulus or anything else? You may have another underlying issue.
= form_with(model: guest, multipart: true, local: true, id:"new_gues") do |form|
avatar file field in form.html.haml
.dropzone.dropzone-default.dz-clickable{"data-controller" => "dropzone", "data-dropzone-max-file-size" => "2", "data-dropzone-max-files" => "1"}
= form.file_field :avatar, direct_upload: true, class: 'form-input py-10', accept: 'image/png, image/jpeg, image/gif, image/tiff', size_limit: 2_000_000, data: { target: 'dropzone.input' }
.text-gray-600.dropzone-msg.dz-message.needsclick
%h3.text-base.font-bold.dropzone-msg-title Drag or click to upload your Company logo
%span.text-xs.dropzone-msg-desc
Choose a square image with a solid background colour of at least 100x100px.
- if @guest.avatar.attached?
= image_tag(@guest.avatar, class: "rounded-full h-20 w-20 mx-auto mt-2")
The strange thing is, I this app was working fine for weeks, and after switched from ERB to HAML, that happened. Also, I have User model by devise, where uploading avatar works very well as you expect it, where I don't use dropdown JS or any JavaScript library!!!
I just pulled down the source for this episode and tried things out. It worked (once I updated an unrelated issue sass-rails). What ActiveStorage storage mechanism are you using?
After days for searching, trying new solution and new code asking on SO, I decided to start fresh 🙁
It is hard since I have been working on this project for weeks. But nothing I can do. Maybe, a fresh start is a good way to inspect code again and think of new way to design and implement features.
☒ By chance, are you overriding ActiveStorage::DirectUploadsController#create? I've pulled your view code and stimulus controller code into the project, updated to Rails 6.1.3.1, updated yarn packages (active storage, ujs and dropzone). It still works locally.
☒ No I haven't override ActiveStorage::DirectUploadsController#create. I don't know what cause this issue. I have created a mini/test app with Rails 6.1.3.1, stimulus, active storage, dropzone, ujs and it works fine. I tried different dropzone_controller.js code, and no issues. Then I tried to replicate my original app, using one model that relay on heavily on dropzone and it works fine.🤷🏻♂️
I would guess HAML caused some issues, because switching from ERB to HAML was the only major change I've made across the app. It was working fine for 4 weeks. Lesson learned, never do a major switch after long development time.
☒ Personally, I'm not a fan of Less/HAML, but one thing that you could try doing is to inspect the rendered HTML from both scenarios to see if there is any difference. There could be one little change that is causing the whole smash to do something strange.
resizeHeight and resizeQuality don't seem to be affecting the uploaded image in any way. I'm wondering if maybe it has something to do with direct_upload...maybe those options are never triggered. Did you play with these settings when using DropzoneJS?
So, if I attach a 1 megabyte 800x800 image...I'm expecting to get back a 50px image that looks pretty bad (due to resizeQuality 0.1). However, I get back the same image I originally attached. No compression or size changes at all.
Also, I'm curious if you know...by default will DropzoneJS upsize? Or, is it smart enough to not upsize? Also, is it smart enough to skip resize options for non-images? The docs don't specify.
☒ I haven't messed around with those options to know if they are making any difference or not. You could always make a custom upload controller, use the new url instead of "this.url" which is taken from the direct upload, and return a variant record. However, you'd still have the full size image stored via ActiveStorage and may need to clean those up periodically.
This is great! I do have an issue in production. I think it might be where I ran yarn add dropzone. I am using an Ubuntu server on DigitalOcean. My dev environment is all Ubuntu. I ran yarn add dropzone in my root directory for the app, installed but same result as below. Then I ran it in my root directory and had the same result below. Then I tried to run it in my myapp/current directory. Maybe its something else. Just looking for some ideas to try
☒ Can you post the relevant bits of the stimulus controller, any console errors in the browser? Typically, it would error out in the assets compilation if there is a missing asset or something that you're referencing.
☒ Thanks for replying! I do have 3 errors pop up on the console, first one being
Access to XMLHttpRequest at 'https://uatmyskiswap.sfo3.digitaloceanspaces.com/mtn1067cgyun59enm7tg5pepje…Signature=9a216bd…'
from origin 'http://uat.myskiswap.com' has been blocked by CORS policy:
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin'
header is present on the requested resource.
Maybe this is the issue or a separate one. The second one is
dropzone_controller.js:29 Uncaught TypeError: Cannot read property 'signed_id' of undefined
at dropzone_controller.js:29
at e.callback (activestorage.js:879)
at e.value (activestorage.js:841)
at XMLHttpRequest.<anonymous> (activestorage.js:815)
The error above comes from the this.hiddenInput.value = blob.signed_id below
☒ This is a CORS issue likely due to the JS doing a “direct upload”. In order to fix this, you will need to change the digital ocean spaces CORS settings. You would likely have this same problem if you were using active storage direct uploads without drop zone.
☒ Thanks! The CORS solved the issue of it uploading, but the animation upload still is not working. Works in dev but not once I upload it, not really sure why maybe i am missing a library in staging? Ill keep messing around see if I can figure it out. If you have any suggestions let me know. No console errors either
☒ -> The resizeWidth dropzone option doesn't work b/c the autoqueue:false bypasses the calling of transformFile in the dropzone source. Trying to figure out right now where to call transformFile. There are also several "solutions" on SO.
☒ I wasn't aware that autoqueue:false bypasses the calling of transformFile. Thanks for pointing that out. Did you end up figuring out a way to call transformFile?
☒ Nope, unfortunately not. I tried to hook into it and call it from my Stimulus controller, but of course the `this` scope got all screwed up. Let me know if you use it! I'm looking to use another library or do it manually.
☒ Thanks for the great video and the simple setup! I've been banging my head against trying to display the photos that are already stored, when I open my form. I did something like this:
The dataset gives me the external url (in this case on cloudinary), but I can't seem to use the displayExistingFile method w external urls... How would you go about displaying exising images in DZ?
P.S. Maybe for a follow-up screencast: How to delete them again from the db? And maybe as a bonus: Make them sortablejs?
Another tool in the tool belt!
Thank you,
Chris
Also, do you have
In your event model?
Yup, I do have
These are my errors.
Started POST "/rails/active_storage/direct_uploads" for 127.0.0.1 at 2020-11-30 23:45:46 +0700
<Error>
this.callback('Error storing "' + this.file.name + '". Status: ' + this.xhr.status);
var blob = new BlobRecord(_this.file, checksum, _this.url);
notify(_this.delegate, "directUploadWillCreateBlobWithXHR", blob.xhr);
blob.create(function (error) {
if (error) {
callback(error);
import Dropzone from "dropzone";
import 'dropzone/dist/min/dropzone.min.css';
import 'dropzone/dist/min/basic.min.css';
import { DirectUpload } from "@rails/activestorage";
export default class extends ApplicationController {
static targets = ["input"]
connect() {
Dropzone.autoDiscover = false
this.inputTarget.disable = false
this.inputTarget.style.display = "none"
const dropzone = new Dropzone(this.element, {
url: '/',
maxFiles: '10',
maxFilesize: '10',
autoQueue: false
})
dropzone.on("addedfile", file => {
setTimeout(() => {
if (file.accepted) {
const upload = new DirectUpload(file, this.url)
upload.create((error, blob) => {
this.hiddenInput = document.createElement("input")
this.hiddenInput.type = "hidden"
this.hiddenInput.name = this.inputTarget.name
this.hiddenInput.value = blob.signed_id
this.inputTarget.parentNode.insertBefore(this.hiddenInput, this.inputTarget.nextSibling)
dropzone.emit("success", file)
dropzone.emit("complete", file)
})
}
}, 500)
})
}
get url() {
return this.inputTarget.getAttribute('data-direct-upload-url')
}
}
"undefined" on console.log(blob)
This is how I solved.
1. create cors.xml
2. parse cors.xml to DigitalOcean Sapces through s3cmd by "s3cmd setcors cors.xml s3://{bucket_name}"
s3cmd installation:
https://www.digitalocean.com/docs/spaces/resources/s3cmd/
Your dropzone_controller.js code is the most simple and comprehensive, and it's a great starter compare to others in my opinion!
Thank you so much for your help David!
Can I also request you for the StimulusJS and Datatable.net tutorial?
I figured out my datatable_controller.js as below. I hope it is useful to the community members here :D
Thanks for your videos 😀
While I'm trying your example, I got an error:
Console errors...
Network error shows it AJAX call issues...
And here is what triggered the issue.
Any idea what could cause such error?
Thanks...
This does seem to be the issue. What does the form and stimulus controller look like?
avatar file field in form.html.haml
The strange thing is, I this app was working fine for weeks, and after switched from ERB to HAML, that happened.
Also, I have User model by devise, where uploading avatar works very well as you expect it, where I don't use dropdown JS or any JavaScript library!!!
If you revert back to ERB, do you get the same issue?
How would I use direct upload instead of file_field?
It is hard since I have been working on this project for weeks. But nothing I can do. Maybe, a fresh start is a good way to inspect code again and think of new way to design and implement features.
Thanks for your help David 😀 👍🏼
I have created a mini/test app with Rails 6.1.3.1, stimulus, active storage, dropzone, ujs and it works fine. I tried different dropzone_controller.js code, and no issues.
Then I tried to replicate my original app, using one model that relay on heavily on dropzone and it works fine.🤷🏻♂️
I would guess HAML caused some issues, because switching from ERB to HAML was the only major change I've made across the app. It was working fine for 4 weeks.
Lesson learned, never do a major switch after long development time.
resizeHeight and resizeQuality don't seem to be affecting the uploaded image in any way. I'm wondering if maybe it has something to do with direct_upload...maybe those options are never triggered. Did you play with these settings when using DropzoneJS?
My Dropzone_controller looks like this:
So, if I attach a 1 megabyte 800x800 image...I'm expecting to get back a 50px image that looks pretty bad (due to resizeQuality 0.1). However, I get back the same image I originally attached. No compression or size changes at all.
Also, I'm curious if you know...by default will DropzoneJS upsize? Or, is it smart enough to not upsize? Also, is it smart enough to skip resize options for non-images? The docs don't specify.
Perhaps this is better suited for StackOverflow.
Thanks!!!!
Maybe this is the issue or a separate one. The second one is
The error above comes from the this.hiddenInput.value = blob.signed_id below
The last error is because the of the error above which just doesn't create
When I don't use dropzone I don't have this issue uploading files or avatars
Here is the staging site
Here is dev environment
P.S.
Maybe for a follow-up screencast: How to delete them again from the db?
And maybe as a bonus: Make them sortablejs?