I am attempting to upload an image to active storage in my Rails backend. I currently have the backend setup correctly but I am struggling to understand FormData. Here is what I have.
The on change function is listening for a change in the input which is of type 'file'. When I add the photo to the input I can get the info from e.target... However I don't know what to add as the URI here. The e.target.value here is a uri that is protected. So I'm confused about how this is supposed to work:
By the way, setFile is just setting 'file' to that object. I am using react.
const onChange = (e) => {
console.log(e.target.files)
setFile({
uri: e.target.value,
name: e.target.files[0].name,
type: e.target.files[0].type
})
}
const onSubmit = () => {
console.log(file)
let imageURI = file.uri
let formdata = new FormData();
formdata.append("image", { uri: imageURI, name: `${file.name}`, type: `${file.type}` })
formdata.append("image", file)
requests.postImageToCurriculum(66, formdata)
}
if you are using Active storage, use their js package
import { DirectUpload } from "#rails/activestorage"
class Uploader {
constructor(file, url) {
this.upload = new DirectUpload(this.file, this.url, this)
}
upload(file) {
this.upload.create((error, blob) => {
if (error) {
// Handle the error
} else {
// Add an appropriately-named hidden input to the form
// with a value of blob.signed_id
}
})
}
directUploadWillStoreFileWithXHR(request) {
request.upload.addEventListener("progress",
event => this.directUploadDidProgress(event))
}
directUploadDidProgress(event) {
// Use event.loaded and event.total to update the progress bar
}
}
link here
Related
I'm trying to create a multi-upload drag and drop with React and react-dropzone. Everything works great, except that I can't seem to get the progress information for the uploads even though I'm using onUploadProgress with Axios.
Here's the code I'm using:
const onDrop = useCallback((acceptedFiles) => {
acceptedFiles.forEach((file) => {
let response = axios.put(`/api/files-endpoint`, file, {
onUploadProgress: (progressEvent) => {
console.log(`progress ${progressEvent}`);
},
});
});
setFiles(acceptedFiles);
}, []);
Am I doing something wrong? In the browser I have tried with both firefox and chrome, even throtthling the connection to slow 3g to see if it will trigger the condition on those circunstances but still no luck. Any help is appreciated.
The upload example in the axios repo uses a FormData object, try adapting your code to use FormData too
const onDrop = useCallback((acceptedFiles) => {
acceptedFiles.forEach((file) => {
const data = new FormData();
data.append('file', file);
let response = axios.put(`/api/files-endpoint`, data, {
onUploadProgress: (progressEvent) => {
console.log(`progress ${progressEvent}`);
},
});
});
setFiles(acceptedFiles);
}, []);
onUploadProgress: (progressEvent) => {
const { loaded, total } = progressEvent;
let precentage = Math.floor((loaded * 100) / total);
console.log(precentage);
if (precentage < 100) {
console.log(precentage);
}
}
destructure loaded and total variables and calculate the percentage from it.
I am trying to upload the image in react, I used the extension ** react-image-upload**.
I used this code to show images on a webpage
import React from 'react';
import ImageUploader from 'react-images-upload';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { pictures: [] };
this.onDrop = this.onDrop.bind(this);
}
onDrop(pictureFiles, pictureDataURLs) {
this.setState({
pictures: pictureFiles
});
}
render() {
return (
<ImageUploader
withIcon={true}
buttonText='Choose images'
onChange={this.onDrop}
imgExtension={['.jpg', '.gif', '.png', '.gif']}
maxFileSize={5242880}
/>
);
}
}
Now The image is showing on the webpage but I don't know how to upload it and save it to a folder I am trying to use this code.
This line is for onChange
onDrop(pictureFiles, pictureDataURLs) {
this.setState({
picture: pictureFiles
});
}
This line is uploading the image, but I don't know how it will function and if I need to add the backend.
uploadHandler = () => {
const formData = new FormData();
formData.append('file', this.state.picture);
console.log()
let context = 'profile';
service.uploadImage(formData,
this.state.picture,
context, (res) => {
if (res.status === "ERROR") {
console.log("ERROR: ", res);
stopLoading();
}
});
}
And the upload function -
export const uploadImage = (file, fileName, context, onDone) => {
console.log(fileName)
post(encodeURI("/api/upload-files/" + fileName + "/" + context), file, (res) => {
onDone(res.data);
});
};
And the backend code, I am using FastAPI- Python for it-
#router.post("/upload-files")
async def image(image: UploadFile = File(...)):
print(image.filename)
return {"filename": image.filename}
I checked the values and the results are right on backend but on webpage it is showing 422: preprocessing error.
Please give some idea what's the process or some hint so I can complete the code.
I want to upload an image from the client-side and send it to a server in React. I've searched a bit and found that most tutorials/guides upload the image using a 'file' type input, then append it to a FormData object to send to the server.
Do I need to create the formData object or can I send the same way I would use just text/numbers? Would it work with a regular object like this:
const [selectedFile, setSelectedFile] = useState(null);
const onFileChange = (e: any) => {
setSelectedFile(e.target.files[0]);
console.log(e.target.files[0]);
};
let newTodo = {
title:'New Todo',
description: 'A new task'
todo_pic: selectedFile,
};
Thanks in advance!
it depends on what the backend program expects, base-64 encoded blob or FormData, what you have to do is appending files to formData or pass form event as initial parameter to that, here is a sample code:
function BlahBlah() {
const [image, setImage] = React.useState(undefined);
const handleOnChangeFile = (event) => {
const imgFile = event.target.files[0];
const reader = new FileReader();
reader.addEventListener("loadend", (val) => {
setImage({
file: imgFile,
blob: val.srcElement.result
});
});
reader.readAsDataURL(imgFile);
};
const handleSubmit = () => {
if (image) {
const formData = new FormData();
formData.append("IMAGE", image.file);
console.log("FormData:", formData.get("IMAGE"));
console.log("base-64 encoded blob:", image.blob);
//here you can use XHR/Axios to upload image, e.g:
/*
axios.post("/file-uploader", (formData OR image.blob));
*/
}
};
return (
<div>
<h1>take a look into console!</h1>
<input type="file" onChange={handleOnChangeFile} />
<button disabled={image ? false : true} onClick={handleSubmit}>
Submit!
</button>
</div>
);
}
sandbox link
i have a bunch of VHD files stored on a private Server, which are accessible through a url.
I am trying upload these vhd files directly to my azure storage account using the azure javascript npm libraries. The vhds have to be uploaded as page-blobs. I tried using the method uploadPagesFromURL() of the pageblobClient but with no success. My code looks roughly like this:
async function uploadVHD(accessToken, srcUrl)
{
try {
// Get credentials from accessToken
const creds = new StorageSharedKeyCredential(storageAccount.name, storageAccount.key);
// Get blobServiceClient
const blobServiceClient = new BlobServiceClient(`https://${storageAccount.name}.blob.core.windows.net`, creds);
// Create Container
const containerClient = blobServiceClient.getContainerClient("vhd-images");
await containerClient.createIfNotExists();
const src = srcUrl.replace('https://', 'https://username:password#');
// Upload to blob storage
const pageBlobClient = containerClient.getPageBlobClient("Test.vhd");
// Get fileSize of vhd
const fileSize = (await axiosRequest(src, { method: "HEAD" })).headers["content-length"];
const uploadResponse = await pageBlobClient.uploadPagesFromURL(src, 0, 0, fileSize);
return uploadResponse;
} catch (error) {
return error;
}
});
It is not possible to upload the Page Blob with your URL directly. You need to read data from the url. Then upload using uploadPages method.
axios.get(URL, {
responseType: 'arraybuffer'
})
.then((response) => {
console.log(response.data)
console.log(response.data.length)
// upload page blob...
}).catch((error) => {
//handle error
});
// uploadPages method
const uploadResponse = pageBlobClient.uploadPages(data, 0, dataLength);
In my application, the user uploads a CSV file in the website, and I need to update the file content (add a few columns) and send it to an API.
So far, I am able to read the file, and transform the CSV content into a JSON object, but I'm stuck in the process of updating the file content and sending it to the API (which needs to receive an object of type File). However, the way that I found is transforming the CSV into an encodeURI.
This is the code:
import { post } from "axios";
class UploadAdmin extends Component {
constructor(props) {
super(props);
// ...
}
onFormSubmit(e) {
if (this.state.file != null) {
e.preventDefault();
// adding the missing columns to the JSON object
const csvObject = this.state.parsedCsvFile;
csvObject["Campaign Name"] = this.state.campaign_name;
csvObject["Campaign Code"] = this.state.campaign_code;
const rows = [Object.keys(csvObject), Object.values(csvObject)];
let csvContent =
"data:text/csv;charset=utf-8," +
rows.map((e) => e.join(";")).join("\n");
// creating CSV file (here the error is happening, since I need to create an object
// with File type to send to the fileUpload() function, but I'm creating an URI)
var newFile = encodeURI(csvContent);
this.fileUpload(newFile)
.then((resp) => {
this.onClear();
this.setState({ modal: true, tipo: "success" });
this.props.getListImport();
})
.catch((error) => {
// handling errors...
} else {
this.onClear();
}
}
fileUpload(file) {
const BASE_URL = `${window.REACT_APP_URL}`;
const formData = new FormData();
formData.append("file", file);
const config = {
headers: {
"content-type": "multipart/form-data",
},
};
return post(`${BASE_URL}/file`, formData, config);
}
Thanks in advance.
To be honest I'm still confused about this, but I don't have time right now. The following may or may not work:
fileUpload(file) {
const BASE_URL = `${window.REACT_APP_URL}`;
const searchParams = new URLSearchParams();
searchParams.append("file", file);
const config = {
headers: {
"content-type": "multipart/form-data",
},
};
const file = new File(searchParams.toString(), "my-file",
{ type: "multipart/form-data" });
return post(`${BASE_URL}/file`, file, config);
}
I changed the FormData to a URLSearchParams. They seem to be very similar types, but URLSearchParams has a toString method which I've called. Then I made it into a File because you said this was necessary, although I'm not convinced that it is. I also renamed it from formData to searchParams.