React / Rails API Image Uploading - reactjs

I've built a React frontend along with a Rails API only backend. I want to allow the user to create a task and enter a title, description and upload an image.
So I've attempted to use DropZone to get access to the image and then send the image info along with the title and description to my Rails API via a post request using Axios.
I set up Carrierwave on my Rails API in hopes of uploading to an AWS S3 bucket once my Task has been added to the database per the post request.
None of this is working so my question is, should I take care of the image uploading to AWS on the react side and if so, how do I associate that image with the additional information I'm saving to my Rails database (title and description).
Thanks!

First, on React side, there should be no proble with title and description, but for image, you need to encode the image to Base64 string. It is something like this.
getBase64 = (callback) => {
const fileReader = new FileReader();
fileReader.onload = () => {
console.log(fileReader.result);
};
fileReader.readAsDataURL(fileToLoad);
fileReader.onerror = (error) => {
console.log('Error :', error);
};
}
Then, on Axios, send those 3 parameters alltogether with one POST request.
For Rails, you need to set up code that can read the Base64 string. Usually, you can use Paperclip or CarrierWavegem to add image attachment. It will look like this.
property_image = listing.property_images.new(param_image)
if param_image[:file_data]
image_file = Paperclip.io_adapters.for(param_image[:file_data])
image_file.original_filename = param_image[:image_file_name]
image_file.content_type = "image/png"
property_image.image = image_file
end
private
def param_image
params.permit(:image, :image_file_name, :file_data)
end

Related

Uploading and reading images to database in base64 format in react

I have an assignment and I need to do it. I'm new to react. There are a lot of resources about uploading pictures on the internet, but they all do it in a different way and it's not what I want. I have a component named product upload in functional component format, and when uploading a product, I want the user to select an image from their computer and upload an image to the product, but this will be in base64 format. At the same time, I need to read the pictures of the products from the database, since I will bring this picture while fetch the products. and the user can cancel the image he selected while uploading the product. Can you make a sample react code with these items? really important. I'm new to React and I don't know much about it.I need to do this.
To summarize briefly, I am writing below in bullet points.
1. the user will select an image from his computer and when he
selects this image, it will appear on the screen in a certain size.
2. if the user clicks the upload button, this image will be
uploaded to the database in base 64 format.
3. if the user presses the cancel button, for example, it may be next
to the picture. The picture selected by the user will be
cancelled.
4. Lastly How can I read the picture information in this database and bring the picture back
to the screen.
I will try to briefly summarize what you need to do and provide a minimal working example.
You need to understand before continuing:
What are Client and Server
HTTP Request Get/Post etc
SQL Database
You need a server. The server will receive the base64 image and store it in the db. It also needs to provide a way to request sending the image back.
For your basic example you can use the python webserver. We use sqlite in python to manage the database.
from http.server import BaseHTTPRequestHandler, HTTPServer
from sqlite3 import connect
if __name__ == "__main__":
db = connect('database.db')
cursor = db.cursor()
cursor.execute(
'CREATE TABLE IF NOT EXISTS images (id INTEGER PRIMARY KEY, base64 TEXT)')
class ServerHandler(BaseHTTPRequestHandler):
def do_GET(self):
cursor.execute("SELECT base64 FROM images LIMIT 1")
image = cursor.fetchnone()
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.send_header('Content-Length', len(image))
self.end_headers()
self.wfile.write(image)
def do_POST(self):
content_length = int(self.headers['Content-Length'])
post_body = self.rfile.read(content_length)
cursor.execute(
"INSERT INTO images (base64) VALUES (?)", (post_body,))
db.commit()
self.send_response(200)
self.end_headers()
webServer = HTTPServer(("localhost", 8080), ServerHandler)
print("Server started")
try:
webServer.serve_forever()
except KeyboardInterrupt:
pass
webServer.server_close()
db.close()
print("Server stopped.")
For the client side aka your react script take a look at the following component. It has an HTML input element that accepts images.
on upload, the image is converted to base64. We then use fetch to send the data to the post method of our python server.
import React from "react";
export default function ImageUpload() {
function convertBase64(file) {
return new Promise((resolve, reject) => {
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = () => {
resolve(fileReader.result);
};
fileReader.onerror = (error) => {
reject(error);
};
});
}
async function uploadImage(event) {
const file = event.target.files[0];
const base64 = await convertBase64(file);
fetch("http://localhost:8080/", {
method: "POST",
headers: { "Content-Type": "text/plain" },
body: base64,
});
}
return (
<input
type="file"
id="img"
name="img"
accept="image/*"
onChange={uploadImage}
/>
);
}
Now you got the basic idea but there's a lot of work todo.
Make the python server better by sending correct responses, validating that the input is base64 encoded, etc. Come up with a good SQL table to store your images. Make sure the image you want is returned. For the frontend make the component pretty. Write another component that displays the image from the db. catch errors and lots more...

Upload Image to Supabase Storage Using Storage APIs

Supabase is wonderful !! I am trying to upload an image to the public bucket using POST request to <SUPABASE_URL>/storage/v1/object/<BUCKET_NAME>/<IMAGE_NAME>.
The difficult is I have only base64 encoded image string and I am not able to make a successful request to above endpoint. Have tried numerous iterations of setting Content-type but no luck.
I am trying to upload my image from Appsmith which provides base64 format for the image from where I will have to hit the above endpoint.
Please help me out here.
I'm glad to be able to find another Supabase fan like me!
I hear your pain. Could you try this technique to convert base 64 string to a blob object?
const byteCharacters = atob(b64Data);
const byteNumbers = new Array(byteCharacters.length);
for (let i = 0; i < byteCharacters.length; i++) {
byteNumbers[i] = byteCharacters.charCodeAt(i);
}
const byteArray = new Uint8Array(byteNumbers);
const blob = new Blob([byteArray], {type: contentType});
The blob variable at the end is the variable you can use to upload to Supabase.
Also, have you considered using the Supabase-js SDK? It will make your life a lot easier as they provide better API's to interact with Supabase.
You can get the supabase-js package here:
https://www.npmjs.com/package/#supabase/supabase-js
And you can find some sample code here:
https://supabase.io/docs/reference/javascript/storage-from-upload
In your case, you could do something like this to upload your file:
const { data, error } = await supabase
.storage
.from('avatars')
.upload('public/sample.png', blob, {
cacheControl: 3600,
upsert: false
})

Upload documents from a web from in react using FormData() is not working

I am creating a simple form in react with a couple of fields and an button to select a file from your pc and upload it. But I have a problem with uploading the file. I am using FormData() for creating the "file" object. This is the code from my Saga (I am using redux saga also):
function* upload(action) {
const payload = action.payload
const data = new FormData()
payload.files.map((file) => {
data.append("file", file)
})
data.append("code", payload.code)
.....
}
The problem is that data object is constantly empty and in the back-end I am sending a null object. Can someone check if I am using FormData() wrong or why is data object empty? Or maybe suggest me a way of how I can develop a functionality for uploading a file in my form?
Thanks.

Upload images to Azure blob from front end (React)

The front end enables people to upload their photos, so i was sending the base64 to the server and working with it initially, but there are problems with firewall which blocks the request which contains base64. As an alternative solution I was trying to upload the image to azure blob get the file name and then send that to the server for processing where I generate a sas token for the blob validation and processing.
This works perfectly fine when I work locally and the front end connection works with #azure/storage-blob
and uploadBrowserData() when I send the arrayBuffer as the param
export const uploadSelfieToBlob = async arrayBuffer => {
try {
const blobURL = `https://${accountName}.blob.core.windows.net${sasString}`;
const blobServiceClient = new BlobServiceClient(blobURL, anonymousCredential);
const containerClient = blobServiceClient.getContainerClient(containerName);
let randomString = Math.random().toString(36).substring(7);
const blobName = `${randomString}_${new Date().getTime()}.jpg`;
const blockBlobClient = containerClient.getBlockBlobClient(blobName);
const uploadBlobResponse = await blockBlobClient.uploadBrowserData(arrayBuffer);
return { blobName, blobId: uploadBlobResponse.requestId };
} catch (error) {
console.log('error when uploading to blob', error);
throw new Error('Error Uploading the selfie to blob');
}
};
When I deploy this is not working, the front is deployed in the EastUs2 location and the local development location is different.
I thought the sasString generated for anonymous access had the timezone option so I generated 2 different one's one for local and one for hosted server with the same location selected.
Failed to send request to https://xxxx.blob.core.windows.net/contanainer-name/26pcie_1582087489288.jpg?sv=2019-02-02&ss=b&srt=c&sp=rwdlac&se=2023-09-11T07:57:29Z&st=2020-02-18T00:57:29Z&spr=https&sig=9IWhXo5i%2B951%2F8%2BTDqIY5MRXbumQasOnY4%2Bju%2BqF3gw%3D
What am I missing any lead would be helpful thanks
First, as mentioned in the comments there was an issue with the CORS Settings because of which you're getting the initial error.
AuthorizationResourceTypeMismatchThis
request is not authorized to perform this operation using this
resource type. RequestId:7ec96c83-101e-0001-4ef1-e63864000000
Time:2020-02-19T06:57:31.2867563Z
I looked up this error code here and then closely looked at your SAS URL.
One thing I noticed in your SAS URL is that you have set the signed resource type (srt) as c (container) and trying to upload the blob. If you look at the description of the kind of operations you can do using srt=c here, you will notice that blob related operations are not supported.
In order to perform blob related operations (like blob upload), you would need to set signed resource type value to o (for object).
Please regenerate your SAS Token and include signed resource type as object (you can also include container and/or service in there as well) and then your request should work. So essentially your srt in your SAS URL should be something like srt=o or srt=co or srt=sco.
I couldn't notice anything wrong with the code you mentioned about, but I have been using a different method to upload files to Azure Blog Storage using React, the method is exactly the same as in this blog article which works perfectly for me.
https://medium.com/#stuarttottle/upload-to-azure-blob-storage-with-react-34f37805fdfc

ReactJS image/pdf file download not working

I want to download file that can be in any format viz. pdf, jpeg, png, xlsx, csv etc. The download API on backend using pyramid framework is sending FileResponse as below:
def delivery_item_download_view(request, *args, **kw):
context = request.context
item_row = context.item_row
if item_row and item_row["deleted_at"] is None:
print(request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"])
response = FileResponse(
request.upload_dir+'/'+item_row["file_name"]+'.'+item_row["file_extension"],
request=request,
)
response.headers["attachment"] = item_row["name"];
return response
This, when executed using POSTMAN works as expected giving file as output. However,when tried implementing same using ReactJS, it's not working as expected. My client-code is as below:
onDownloadItem= (item) => {
console.log("item id is:", item.item_id)
var apiBaseUrl = "https://dev.incodax.com/api/deliveries_items/"+ item.item_id+ "/download";
fetch(apiBaseUrl, {
method: "GET",
}).then((res) => {
fileDownload(res,item.file_name)
console.log(res)
})
}
This fileDownload function simply downloading file but with no content inside. In downloaded file I could see something like:
[object Response]
I am getting 200 response from server. So I dont't think there is any issue with server side code. How can I handle it on client?
Thanks in advance
Will it suit you if you just redirected user to link to file? Browser will automatically handle it and download it.
The issue is in your fileDownload function which you do not post here. It's not clear what the first parameter is supposed to be but likely it is not the response object. Likely you at least need to pull the body out of the response and save that! The response body can be converted to a buffer object which could work (again it depends on what fileDownload is expecting):
res.arrayBuffer().then(buffer => {
fileDownload(buffer, item.file_name);
});

Resources