Uploading files in a React/Rails App using Active Storage
Tags: react, ruby, rails, database
Published: 2021-09-28 05:23:41

Uploading files is a common thing that we do on the internet.  Uploading images to Instagram, uploading audio files to SoundCloud, uploading videos to Youtube, uploading images to this blog, etc.  If you are looking to integrate a feature like this into your React/Rails application, I got you.  In this blog I will be using __postgresql__ for the database and I will be dealing with audio files such as mp3, wav, etc.  Thanks to [Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html), the process for doing this is not as complicated as you might think.

##Backend setup
Run this in your console:
```
rails active_storage:install
```
This will create 2 tables that you can view in your `./db/migrate` folder, then run:
```
rails db:migrate
```
If you check your `schema` this is what you should see:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/set9svkygkiz6eug9cv6.png)
Don't worry too much about these for now, I will be linking other helpful blogs at the bottom that explain more in detail about how these tables work under the hood if you want to know more.

####has_one_attached macro
This macro will magically associate a file attachment to whatever model you apply it to.  In the context of this example, I want a user to be able to upload beats with an audio file attached.  You can name the macro whatever you want I just decided to call it `:audio_data` (e.g. :audio, :audio_file, :image, :picture, etc) I recommend naming it with a description that matches the type of file you are going to be working with:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/whx21f7glxe9lf1lfvz1.png)

####Controller
Make sure to add it to your controller params:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7ujyrt5pf4b3nmd926t2.png)

####Serializer
Your serializer should look something like this, make sure to include __line 2__ and just replace `audio_data` with whatever you named it:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lluldezqv5erziqeblzp.png)

##Frontend setup
Now that our backend is ready to handle the upload from the frontend, let's create a basic form:
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/yu5nm5xctr3k9gr1dkp5.png)

####State
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/moj0il40d0vwt92hbu0q.png)

####The form
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/rhfyl428a98ojp2w5tc9.png)
* __input's accept attribute__ - we are setting the value to _"audio/*"_ which allows a user to upload all audio file types.  Use _"image/*"_ for images and _"video/*"_ for videos.
* __onChange__ - with file uploads, they are going to be stored in an array called `files`.  Because we are only uploading 1 file we just access our file at the [0] index.

####Making the POST request to our backend
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5suqj68o73llzlwxmtpt.png)
Files require different packaging than your typical `JSON.stringify()`.  We need to send the body as __formData__ by creating an empty formData object and then appending our state to it.  The right side of the comma is our state we had at the top, make sure the left side of the comma matches what you have in your `schema`.  Don't bother trying to __console.log__ the formData object either, you will just get an empty object.

####Rest of the code
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ozk70kq6j89vvk0ekpy1.png)
Just fetching a user and setting it in state to provide a `user_id`, also fetching from beats to use in the audio player.

##Testing it out
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9n6fy2w9yu03nwqszjqu.png)


##Making a GET request in Postman
![Alt Text](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4jsa3k2pdc5uez5bwi0s.png)
BOOM!!  After submitting, you can now make a GET request to your server and see that your upload was successful!  

##Enjoy the fruits of your labor
{% vimeo <616666155> %}
Clicking that play button is a great feeling.  Now go sicko mode and unleash your new file uploading powers!!  Below are resources that really helped me accomplish this, please let me know in the comments below if there is anything important I may have left out.


##Resources
[HTML input accept Attribute - W3Schools](https://www.w3schools.com/tags/att_input_accept.asp)
[FormData() - MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData/FormData)
[Using FormData Objects - MDN](https://developer.mozilla.org/en-US/docs/Web/API/FormData/Using_FormData_Objects)
[Active Storage](https://edgeguides.rubyonrails.org/active_storage_overview.html#cross-origin-resource-sharing-cors-configuration)
[How to upload mp3s to your rails backend using active storage](https://medium.com/@noahshafer0211/how-to-upload-mp3s-to-your-rails-backend-using-active-storage-83baaed3395a)
[React File Uploads to Rails](https://medium.com/swlh/react-file-uploads-to-rails-cc9c62e95a9d)
[Upload images to your Rails API from React the easy way](https://medium.com/swlh/upload-images-to-your-rails-api-from-react-the-easy-way-241bbe71ea85)
[React Audio Player](https://www.npmjs.com/package/react-audio-player)