Image Upload in React with a Rails API
Having just finished my final portfolio project at the Flatiron School, I thought it would be helpful to do a brief walkthrough of my process for a key item that I had some trouble with. For some background, I created a closet app for a user to track inventory of their clothing items. For this to be a functional app, I thought it was imperative that a user be able to upload an image. I am going to go over how I made this possible below.
Let’s start with the backed of my project. After generating an Item resource for my project, I looked into Active Storage for Rails. Per the Rails guide, Active Storage facilitates attaching files to Active Record objects which was exactly what I needed. I ran “rails active_storage:install” to generate the migration that created the necessary tables to move forward, followed by “rails db:migrate” to get working. This created a file called “create_active_storage_tables” as seen in detail below.
Once that was created, I went into my Item model and indicated that an item wold have an attached image as follows:
I also indicated that an image would be attached in the Items controller’s index action as follows (note that my API already has a current_user method and JWT authentication already set up. To simplify, I initially started with “render json: Items.all.with_attached_image” to test).
To follow, I built a serializer with intention that the API would include a unique link to an image if an image were uploaded to an item. If an image were not uploaded while creating an item, I provided a link to a default image in this situation (default image is in the public folder of the Rails API).
After testing this out, I moved onto the front end of the project. First, I created the form and associated functions for submitting my item in a specific component designated to this feature (please note, I removed the various inputs in the code below to simplify). The initial state of this component was set per usual. I noted that this form should accept any type of image for the image input.
As you can see in the code above addItem is a prop in the handleSubmit function. Since I used redux in my project, I mapped dispatch to props in the container in which this component was renders. The associated redux action that was mapped to this prop in below. Please note that since I used redux as well, I also had a simple reducer in the app (not included in this project) as is noted in this action.
What I found extremely important to note is the use of formData in the above code. Upon research, I learned that FormData objects are used to capture HTML form and submit it using fetch or another network method. Specifically, it is most useful in this case with capturing file uploads. Prior to my use of formData, my images were not able to be saved to my backend. One I tested this out/confirmed that my backend and front end were communicating properly, I moved on to rendering the images in my user interface.
Remember how I created a link in the item serializer on the backend? With that accessible in each item instance created, I added this to my image tag by passing it through as a prop in my Item component.
I then updated my Items component (which renders the Item component) as follows. Please note that my Rails server is running on localhost:4000.
As my app incorporates redux, the items prop used in the above is connected to the redux store in this Items component’s container component (not included in this blog). This gives us access to all the items in our database by fetching them upon load of the page and updating the store and the database (as seen in our add redux action included above) every time a new item is created.