Uploading Images To A Rails Backend from a React Frontend
Welcome to this weeks blog, I’m so glad you’re able to join me! This week I want to cover a topic that pertains to a project I’m working on currently. In my project, I had to include the ability for users to upload images from their local drive to a Rails backend. It took me a while to figure out how to get this completed, but now that I’ve got it, hopefully this guide will help you include this in your next React/Rails app.
Let me break down the process before we get into each of the steps. First, you will need to set up an account with Cloudinary. Cloudinary is a cloud-based image and video management platform where the image will actually be stored. Essentially, what Cloudinary does is stores the image and develops a url for the image that can be used on you application.
Once you set-up your Cloudinary account, you will integrate it to your Rails API using the credentials you create with your account. Once the backend is integrated, I will show you how to send the data back to your API using FormData. Let’s get started!
Setting Up Your Cloudinary Account
Start by creating your account with Cloudinary using the link below.
Once you create your account, you will be redirected to a dashboard that includes the credentials necessary to integrate to your Rails API.
The account details will be listed at the top of the dashboard like the image above. My personal details have been marked out for obvious reasons, but you will need the Cloud name, API Key, and API secret to integrate to your backend.
Integrating Rails API to Cloudinary Account
If you haven’t already, set up your Rails API by generating your models and controllers and create the database and migrate. If you don’t know how to set up a Rails API check out this link.
Let’s start by navigating to config/application.rb. Go into the file and uncomment the code below and replace ‘example.com’ with ‘*’.
Essentially, the Rack middleware is used for handling Cross-Origin Resource Sharing (CORS), which makes cross-origin AJAX possible. To simplify, the middleware allows the backend to accept resource requests from certain origins. However, by replacing the ‘example.com’ with ‘*’, we are accepting all resources from any origin.
Now, let’s create a new file called cloudinary.rb in the config/initializers folder. This is where we will need to use the credentials we created when we set up our Cloudinary account. In the file, copy the following configuration.
Make sure you replace the cloud name, api_key, and api_secret with the credentials from your Cloudinary account. As they appear above, make sure that each of the credentials are wrapped in strings.
You will need to make sure you include the cloudinary gem to your Gemfile. Include, gem ‘cloudinary’, to the file and bundle install your gemfile before starting the rails server.
Now let’s go to the controller, specifically the create method of the controller, where we will send up the image from the client to Cloudinary. Once we upload the image successfully, Cloudinary will send a response containing the URL string of the image. What we will store in our Rails database is not the actual image but the URL string to where it is stored in Cloudinary.
We will begin by setting up the method to upload images to Cloudinary in the create method in the controller. If you remember the Cloudinary gemfile we added, the gemfile actually inherits methods from Cloudinary. The one method we will be utilizing is Cloudinary::Uploader.upload(). The method will accept one argument, the image.
In the create method of the controller, start by establishing an image variable that will accept the image sent to the controller and send it to Cloudinary using the method from the gemfile. Just like I have done, below.
image = Cloudinary::Uploader.upload(params[:image])
Then, in the create method, you can create a new instance of an object using the url of the image sent back from Cloudinary. The example below is based on creating an instance of Item with the attribute of item_image with the image we defined above. In order to get the url, we include [“url”] after the variable.
item = Item.create(item_image: image[“url”])
Once the Item instance is created, we are now able to render it to our database and render it as JSON.
Sending Requests from the React Frontend to the Rails Backend
What’s tricky with uploading files from the frontend is that unlike typical POST requests, instead of just an object being sent back to the Rails backend, we need to send back a form. There are some slight changes to your normal AJAX request that you will need to adjust in order to send the information back. Let’s dig into it!
According to Mozilla Developer Network (MDN), the FormData object lets you compile a set of key/value pairs to send using XMLHttpRequest. It is primarily intended for use in sending form data, but can be used independently from forms in order to transmit keyed data. The transmitted data is in the same format that the form’s submit method would use to send the data if the form's encoding type were set to multipart/form-data.
So let’s look at an example where we create a new FormData object to send back to our backend.
The image above is an example of a submit method() for a form in my project. I started with the preventDefault() to make sure that if the event does not get explicitly handled, its default action should not be taken as it normally would be. Then, I created a new FormData object and called it formData. I added key/value pairs with the information I collected from the form and used the .append() method from the FormData object. As arguments, I passed through the name of the attribute as the key and the information collected as the value. Once I appended all of information collected from my form, I passed the FormData object to a function called savePost where I make the fetch request. The POST request is shown below.
In the request above, the FormData that we passed through in the submit handle is represented as ‘postObj’. (Disregard the return function and dispatch, I used Redux to handle state, if you want to learn about Redux I recommend going here) If you look at the fetch request, it is written as normal but the important thing I wanted to show is that in the headers object, there is no content-type key included. Make sure that it is NOT included in the headers because as I stated earlier about FormData objects, they are sent using XMLHttpRequest and not in JSON. when you include the content-type: “application/json” key value pair, it’s telling the backend that the data being passed in in JSON form, which it is not. If it is not removed, you will run into an error and the FormData cannot be passed.
Well, these are the essential steps to understanding how to set up your Rails Backend and React Frontend to accept image files from a local host. Hopefully, this guide was easy enough to follow along with so you include it into your project. Just note that with many topics in software development, there are a multitude of ways to accept files, but this is how I chose to do it. As always, I challenge you to continue doing your own research on the topic if this walkthrough is not helpful. I also encourage you find other methods that may be easier or more efficient. Thanks again for joining me and I hope to see you next week!