Uploading User picture to Rails API and React App. #part 2

Julia
5 min readNov 7, 2020

First part of the blog was about setting up your Rails backend for being able to attach photo to a user. Here is a link in case if you missed.

This blog is going to be mostly about Front end of the App. I am skipping the creation of React App and User Profile Component (I assume you already have it). I am going to stick to a topic of this blog and start straight with Photo Uploader Component. Here is my render method, which return:

  • Form for selecting an image file from your local machine,
  • Image preview,
  • Upload button

Attribute type with value "file" allows user to select and input a file. The accept attribute can only be used with <input type=”file”> and specify the allowed file type. So if you want the user upload only JPEGs and GIFs file types set corresponding value: accept="image/gif, image/jpeg" OR accept=".gif,.jpeg" It work both ways. accept="image/*" allows user to upload any type of images.

Explanation onChange, onSubmit events and filePreview() method.

changeHandler method set the selected by user file in the component state.

filePreview method displays the selected image thumbnail. For implementing this I used URL.createObjectURL() method provided by the Web API . The method creates a DOM URL representing the object given in the parameter. Here is the result I got, great image preview!

Useful tip! “Choose files” text on the button is pre-defined by the browser and can’t be changed. But there is a way to hide the file name using CSS:

input[type='file'] {color: transparent;}

And lastly onSubmitevent envokes protoUploader method.

protoUploader method creates a formData object with the key and value pair. In my example the key is “photo”, you can name it whatever. The value is the selected file that stored in the Component State. formData()method primary used to capture HTML form input as object and send it using HttpRequest. Ensure not to include "Content-Type' : "application/json to the header of request, it will cause a bug !!!

Going back to the Rails backend.

Now we need to go back to the backend and add a custom route and a method for posting the image.

In config/routes.rb:

post '/users/:id/upload_photo', to: 'users#upload_photo’

In controllers/users_controller.rb:

This #upload_photo method attaches the file to the User using Active Storage method .attach()

For debugging purpose to access your attachment in rails console rails c use the following methods:
User.last.photo.attached? - to check if the image was successfully attached
User.last.photo.blob to access the attachment

Retrieve the image from Cloud and render it in the app I need to know the Url. For implementing that I can let User Serializer know that URL for attached photo should be always rendered with the user object ! That way I can simply use that Url and pass it as src in the <img> for rendering user image. However, there are few options what exactly might be rendered:

  • Url of the image on localhost
  • Url of the image on Cloudinary
  • The blob.key (which is the image id on Cloudinary).

There are 3 lines of code for each option in my #photomethod. If you choose first or the second option simply use those commented lines of code. For the second option you also need to have get_photo_url() method in User Model and add include Rails.application.routes.url_helpers because url_for() is a helper method.

But !!!! I decided to go with a third option and get a blob.key with my fetch response. The reason behind that is because by default Cloudinary uses the blob.key as the id of the image.

You can check it in your rails console:
User.last.photo.blob.key. The key will be the same as the id of the last image on Cloudinary. I need to have the access to those id’s on Cloudinary in order to transform and manage images.

To retrieve transformed images from Cloudinary you need to add some parameters in the url, so if my #photomethod in User Serializer would return image url it might get complicated to modify that url in a right way. Cloudinary has a library that generate those url’s, you only need to specify your cloud name and the image id (which is a blob.key). That is exactly why in my #photomethod I decided to return a blob.key and not the whole url.( If you are not planning to transform user images and simply need to render them in original way, returning Url in #photomethod is the ideal option, you don't need to install a Cloudinary library, just simply pass the URL from fetch response to the <img src=” URL”> in your component and it will render an original user picture in your App.

In the next part of this blog I am going to install Cloudinary Library to my React Аpp and show how to work with image transformation and how to render circled avatars in the App.

--

--