So, you want to save an altered image for later use. Let’s say you want to allow the user to upload a photo, crop it, and save that cropped image as their avatar. Here I am going to go over one solution that I have found for getting the altered image information from React to Rails and attaching that information to the user via ActiveStorage. I will not be covering how to upload a photo, crop it, or how to set up ActiveStorage. For that information, I recommend that you check out the links below.
Now the fun stuff! I am using a handy component called react-easy-crop to crop my images (see above link). It comes with the callback onCropComplete which is passed 2 arguments croppedArea and croppedAreaPixels, and is called when the user stops moving the media or stops zooming. This seems like the logical place to start.
Basically, what we want to do here is get the cropped image and set that information to a state variable. Nice and easy! To do this, we are going to want to create and image from only the cropped section of the image (we will use the information we get from onCropComplete), then return that image as data. The cropImage component is built to do just that.
Here we create a ‘canvas’ element and use .useContext(‘2d’) to create a 2d shape on it. We use the information we passed in from onCropComplete (croppedAreaPixles) to draw only the cropped section of the image on our canvas using .drawImage(). Then we return the canvas as base64. All of this is done using promise-based functions to suspend execution until the returned promise is fulfilled or rejected. This is to make sure the functions have the information they need before moving on. Once we receive the image data from getCroppedImg, we are going to save that information to a state variable. Now, we need to get that information to our Rails back end.
One way to get the image information where it needs to go, is through the existing form where we uploaded the original file. So, in the existing form, we will add an input with the value equal to the state variable that contains the information for the altered image. The ‘name’ of this input will be very important. You will want the name of the input to be the same as the attachment in ActiveStorage… we will circle back to this.
The submit handler is pretty straight forward. We just instantiate a new FormData object and pass in our form, then send that information in the body of a fetch request.
Once that information arrives at our Rails API, we need to attach it to the appropriate user. First lets add some functionality to ActiveStorage. Let’s add gem ‘active_storage_base64’ to our GemFile. Then we will want to add include ActiveStorageSupport::SupportForBase64 to application_record.rb. Now we can attach the base64 image to our user!
To attach the image to the user, just add has_one_base64_attched :foo. Make sure the name of the input that stores the image data in your form and the name of has_one_base64_attached in your model are the same! This is because has_one_base64_attached is going to look for, in this case, a param named ‘profile_img’ to attach to the user. If there is nothing coming in with that name, then it will not attach anything.
Depending on how you have ActiveRecord set up, that’s it! The images that are being uploaded and cropped in the front end, are now being attached to the appropriate user. Happy coding!