Image uploading using reactjs, does not save image path in the database - reactjs

I am using Rails API in the backend and ReactJS in frontend. I am also using carrier-wave for processing my image in the backend. I tried to upload my image and send it to the backend. The image files are being captured in the frontend by using simple HTML uploader.
This is my uploader.jsx
import React from 'react'
import axios, { post } from 'axios';
import { PORT } from '../constant.js';
class PrescriptionNew extends React.Component {
constructor(props) {
super(props);
this.state ={
file: null
}
this.onFormSubmit = this.onFormSubmit.bind(this)
this.onChange = this.onChange.bind(this)
this.fileUpload = this.fileUpload.bind(this)
}
onFormSubmit(e){
e.preventDefault() // Stop form submit
this.fileUpload(this.state.file).then(response => {
console.log('response', response.data)
})
}
onChange(e) {
this.setState({file: e.target.files[0]})
}
fileUpload(file){
const url = `${PORT}/prescriptions`;
var FormData = require('form-data');
const formData = new FormData();
formData.append('file',file)
const config = {
headers: {
'content-type': 'multipart/form-data'
}
}
return post(url,formData, config)
}
render() {
if (this.state.file !== null) {
console.log('this.file', this.state.file.name)
}
return (
<form onSubmit={this.onFormSubmit}>
<h1>File Upload</h1>
<input type="file" onChange={this.onChange} />
<button type="submit">Upload</button>
</form>
)
}
}
export default PrescriptionNew;
The above code is an exact replica of this solution.I have used formData and axios in order to PUSH the data to the backend. But the datas are stored as a "nil" values in the database.
console.log(formData) gives an empty hash.
My Controller code in backend side is
def create
#prescription = Prescription.new(prescription_params)
#prescription.user = current_user
unless #prescription.save
render json: { status: 200, errors: #prescription.errors } and return
else
render :show
end
end
I have also refered many solution given in this portal. But still , cannot able to study whats going wrong in my code.

The simple solution is to populate FormData. Returning an empty FormData will store 'nil' values in the database.
The perfect soution is
class PrescriptionNew extends Component {
upload_image(){
var element = document.getElementById("image-form")
var formData = new FormData(element);
const url = `${PORT}/prescriptions`
fetch(url,{
method: "POST",
body: formData
})
.then(response => response.json)
}
after_submit(event){
event.preventDefault();
}
render(){
return(
<div>
<h3 className="index-title">Upload Your Prescription</h3>
<form onSubmit={event => this.after_submit(event)} id="image-form" encType='multipart/form-data'>
<input type="file" name="image_path"/>
<button onClick={() => this.upload_image()}>Upload</button>
</form>
</div>
)
}
}
export default PrescriptionNew;

Related

How can I upload multiple files in a React form to Flask API?

I am experimenting with React and I am trying to upload multiple images to my API in flask for saving. I was able to figure out how to upload a single file, but am struggling to convert to multiple. Here is the code for single upload.
FLASK
#app.route('/upload', methods={"POST"})
def upload_file():
file = request.files.getlist("file")
print(file)
response="Whatever you wish to return"
return response
REACT
export default class Test extends React.Component {
constructor(props) {
super(props);
this.state = {
};
this.handleUploadImage = this.handleUploadImage.bind(this);
}
handleUploadImage(ev) {
ev.preventDefault();
const data = new FormData();
data.append('file', this.uploadInput.files[0]);
fetch('http://localhost:5000/upload', {
method: 'POST',
body: data,
}).then((response) => {
response.json().then((body) => {
});
});
}
render() {
return (
<form onSubmit={this.handleUploadImage}>
<div>
<input ref={(ref) => { this.uploadInput = ref; }} type="file" />
</div>
<br />
<div>
<button>Upload</button>
</div>
</form>
);
}
}
You could set the multiple property on your file input so you can select multiple files:
<input
ref={(ref) => {
this.uploadInput = ref;
}}
type="file"
multiple
/>
Then you could change your handleUploadImage function so it sends all files selected:
handleUploadImage(ev) {
ev.preventDefault();
const data = new FormData();
for (let i = 0; i < this.uploadInput.files.length; i++) {
data.append("file", this.uploadInput.files[i]);
}
fetch("http://localhost:5000/upload", {
method: "POST",
body: data,
}).then((response) => {
response.json().then((res) => {
console.log(res);
});
});
}

React passing data or adding to state wrong

When I leave this code as is, I will get the correct console.log (commented with "these appear correct") that I'm looking for. However when I replace the api_url with http://localhost:9000/ipdata/${this.state.inputValue} the console.log is blank. This is why I think I'm either passing the input value wrong or I'm adding it to the state wrong.
I would assume I'm adding it to the state wrong as the spans that I'm trying to render in order to output the data on the client aren't displaying anything either.
Heres my code ...
import React from 'react';
import './App.css';
class App extends React.Component {
constructor(props) {
super(props);
this.state = { apiResponse: '', inputValue: '', result: {} };
}
async callAPI() {
try {
console.log('called API...');
const api_url = `http://localhost:9000/ipdata/8.8.8.8`;
const res = await fetch(api_url, {
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
});
const result = await res.json();
// these appear correct
console.log(result.city);
console.log(result.region_code);
console.log(result.zip);
this.setState({ result });
} catch (error) {
// handle errors
}
}
render() {
return (
<div className="App">
<h1>IP Search</h1>
<input
type="text"
value={this.state.inputValue}
onChange={(e) => this.setState({ inputValue: e.target.value })}
/>
<button onClick={this.callAPI}>Search IP</button>
<p>
<span>{this.state.result.city}</span>
<span>{this.state.result.region_code}</span>
<span>{this.state.result.zip}</span>
</p>
</div>
);
}
}
export default App;
API call on the Node server...
const fetch = require('node-fetch');
app.get('/ipdata/:ipaddress', async (req, res, next) => {
console.log(req.params);
const ipaddress = req.params.ipaddress;
console.log(ipaddress);
const api_url = `http://api.ipstack.com/${ipaddress}?access_key=API_KEY`;
const response = await fetch(api_url);
const json = await response.json();
res.json(json);
});
The problem is not the way you set state, but the way you access it, because callAPI doesn't have access to this, so you get an error thrown inside the function and as you don't handle errors, it gets swollen. To make it work you either bind the function
onClick={this.callAPI.bind(this)}
or use arrow function instead
callAPI = async ()=> {

Sending an axios Post request with csv in its body

What i am trying to achieve is send a post request from my frontend to back end using axios.This post request has a csv file in its body.
Using postman : postman request
My code is this:
import React, { Component } from 'react';
import axios from 'axios'
class SessionsUpdate extends Component {
state = {
selectedFile: null
}
handleSubmit = async () => {
let formData = new FormData();
formData.append('file', this.state.selectedFile);
await axios.post(
'https://localhost:8765/...',
formData,
{ headers: { 'x-observatory-auth': localStorage.getItem("token"), 'Content-Type': 'multipart/form-data' } }
)
console.log("log") //this is not printed here
}
onFileChange = event => {
this.setState({ selectedFile: event.target.files[0] });
};
render() {
return (
<form onSubmit={this.handleSubmit}>
<div>
<h1>Choose a file to store</h1>
</div>
<div>
<fieldset>
<input type="file" accept=".csv" onChange={this.onFileChange} />
</fieldset>
</div>
<input type="submit" value="Submit" />
</form>
);
}
}
export default SessionsUpdate;
So the HTML part creates a simple GUI to select a csv file from local storage and what i want is to pass this csv file to my post request.After searching online the main way i found to do this is by using formdata but it does not work on my case and i have been stuck in this for quite a while.This requests works fine on postman though.
Any ideas about what i am missing?

Upload an image with reactjs and mongodb

I'm trying to make an image uploader, thanks to a form, in reactjs.
I've created an api in mongodb (thanks to express, mongoose, etc.), and i'm trying to use it in order to upload an image.
Actually, i would like to send an image file to the cloud (with Cloudinary), and get the url.
That is my form and methods :
class Header extends Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.state = {
data: [],
uploading: false,
image: [],
apiKey: 'xxx'
};
}
onChangeImage = e => {
this.setState({[e.target.name]: Array.from(e.target.files)});
};
sendImage = files => {
const formData = new FormData();
files.forEach((file, i) => {
formData.append(i, file)
});
fetch('http://localhost:3000/image-upload', {
method: 'POST',
headers : new Headers({
'Content-Type' : 'application/x-www-form-urlencoded',
'x-access-token' : this.state.apiKey
}),
body: formData
})
.then(res => res.json())
.then(image => {
this.setState({
uploading: false,
image
});
return true;
});
return false;
};
handleSubmit = (event) => {
event.preventDefault();
const { image } = this.state;
this.sendImage(image);
};
render() {
return(
<form onSubmit={this.handleSubmit} className="formAdd">
<input type='file' id="image" name="image" onChange={this.onChangeImage} />
<button className="contact-form-btn">
Send<i className="fa fa-long-arrow-right" aria-hidden="true"></i>
</button>
</form>
)
}
About my API Controller :
const cloudinary = require('cloudinary');
module.exports = {
create: function(req, res) {
cloudinary.config({
cloud_name: 'xxxx',
api_key: 'xxxxx',
api_secret: 'xxxxx'
});
const path = Object.values(Object.values(req.body.files)[0])[0].path;
cloudinary.uploader.upload(path)
.then(image => res.json([image]));
},
};
The error code that I get is 500 'TypeError: Cannot convert undefined or null to object'.
Indeed, it not found Object.values(Object.values(req.body.files)[0])[0].path.
What I've missed ?
Thanks.
You can use this to upload an image. Using async/await.
async uploadImage(image) {
const form = new FormData();
form.append('file', image);
form.append('upload_preset', 'g5ziunzg');
const res = await Axios.post('YOUR_CLOUDINARY_URL', form)
console.log(res)
return res.data;
}
This will return an object with the secure_url which you can store in your mongo database. I am assuming you have a backend-api for this task.
Inside your formSubmit function, you can first call this function and receive this secure_url.
Note that I am using axios here. This example can easily be translated to work with fetch.
You don't need to use Object.value since req.body.files is an array and you need to check its length before access. Try it:
const [file] = req.body.files
if (file) {
// your logic here
}

Change file name in React-Dropzone image upload with cloudinary

I am using react-dropzone and cloudinary for image upload.
I have already made an successfull connection between my account and my react project and I am able to upload images though my react project.
I am having trouble setting the file name in the react project.
Here is the code snipped of my react project.
I have already tried something like this:
onImageDrop(files) {
console.log(files)
var test = JSON.parse(JSON.stringify(files))
test[0]["name"] = "test"
this.handleImageUpload(test);
}
But I get an error saying that the file is readonly.
Here is the working example of what I have
onImageDrop(files) {
this.handleImageUpload(files[0]);
}
handleImageUpload(file) {
let upload = request.post(CLOUDINARY_UPLOAD_URL)
.field('upload_preset', CLOUDINARY_UPLOAD_PRESET)
.field('file', file);
upload.end((err, response) => {
if (err) {
console.error(err);
}
console.log(response)
});
}
render() {
return (
<div>
<Dropzone
onDrop={this.onImageDrop.bind(this)}cloudinary
accept="image/*"
multiple={false}>
{({ getRootProps, getInputProps }) => {
console.log("input props", getInputProps)
return (
<div
{...getRootProps()}
>
<input {...getInputProps()} />
{
<p>Try dropping some files here, or click to select files to upload.</p>
}
</div>
)
}}
</Dropzone>
</div>
)
}
How do I change the file name before I send it to cloudfire?
You can set the image name on Cloudinary when uploading by setting the public_id.
For example:
import React from "react";
import ReactDOM from "react-dom";
import "./styles.css";
class Upload extends React.Component {
processFile = async e => {
var file = e.target.files[0];
var formdata = new FormData();
formdata.append("file", file);
formdata.append("cloud_name", "XXXX");
formdata.append("upload_preset", "XXXX");
formdata.append("public_id", "my-name1");
let res = await fetch(
"https://api.cloudinary.com/v1_1/<Cloud-Name>/auto/upload",
{
method: "post",
mode: "cors",
body: formdata
}
);
let json = await res.json();
console.log(JSON.stringify(json.secure_url));
};
render() {
return (
<div>
<h3>Upload</h3>
<input type="file" onChange={this.processFile} />
</div>
);
}
}
ReactDOM.render(<Upload />, document.getElementById("container"));

Resources