I’ve been struggling to find a solution to upload an image and store it in the database.
Tried them all: Dropzone, react-dropzone, react-uploader, etc.....
The BackEnd API is expecting this:
{
"course": {
"title": "Hic et velit sed.",
"subtitle": "Omnis quibusdam illum itaque.",
"description": "Et ullam ipsum. Illum dolor odit. Id veritatis ducimus.",
"end_date": "2020-02-01",
"attachment_attributes": {
"file": {
--- here the uploaded data file ---
}
}
}
}
My component is now only written with 1 input type=file to speed up this testing. The API requirements such as title, subtitle etc., will be hardcoded.
Here the component:
import React, { Component } from 'react';
import api from '../../../../helpers/API';
class Uploader extends Component {
constructor(props) {
super(props);
this.state = {
selectedFile: null
}
}
onChangeHandler = event => {
this.setState({
selectedFile: event.target.files[0],
loaded: 0,
})
}
onClickHandler = () => {
** HARDCODED API REQUIREMENT**
const body = "course": {
"title": "Hic et velit sed.",
"subtitle": "Omnis quibusdam illum itaque.",
"description": "Et ullam ipsum. Illum dolor odit. Id veritatis ducimus.",
"end_date": "2020-02-01",
"attachment_attributes": {
"file": {
--- here the uploaded file data ---
}
}
}
** THIS SHOULD HANDLE THE UPLOADED FILE DATA FORMAT **
const data = new FormData()
data.append('file', this.state.selectedFile)
return api
.post("http://localhost:3000/api/v1/files", ??????). <— DATA or BODY?
.then(res => {
console.log(res.statusText)
})
.catch(res => console.log('error ==> ', res))
}
render() {
return (
<>
<div>
<label>Upload Your File </label>
<input
type="file"
multiple onChange={this.onChangeHandler}/>
</div>
<button type="button" className="btn btn-success btn-block" onClick={this.onClickHandler}>Upload</button>
</>
)
}
}
export default Uploader
Issue
If I pass DATA, in the API call, the uploaded file get nicely stored in the Browser > Network > Header > Data Form section, as file: binary
And that is good.
But I need to pass the uploaded file as part of my BODY object. So, below is what I did, but it gets returned empty:
onClickHandler = () => {
const data = new FormData()
data.append('file', this.state.selectedFile)
const body = {
"course": {
"title": "Hic et velit sed.",
"subtitle": "Omnis quibusdam illum itaque.",
"description": "Et ullam ipsum. Illum dolor odit. Id veritatis ducimus.",
"end_date": "2020-02-01",
"attachment_attributes": {
"file": data <-- trying to pass the uploaded DataForm here
}
}
}
return api
.post("http://localhost:3000/api/v1/files", body)
.then(res => {
console.log(res.statusText)
})
.catch(res => console.log('error ==> ', res))
}
Unfortunately I get 422 error, {"errors":{"attachment.file":["blank"]}}
Any help is much appreciated. Thanks
Jow
OK, found the way.
It's impossible to call the DataForm of the uploaded file from the Object BODY.
What it needs to be done is to data.append each single item in the object.
Here the file:
This way, the
Browser > Network > Header > Data Form, will show each item passed correctly and the uploaded image will maintain the binary format.Here a preview:
POST API will be looking like this:
I really hope this can help someone else because it has driven me crazy for weeks.
Happy coding. Joe