Search code examples
ruby-on-railsreactjsrails-activestorage

Upload image using react to active storage rails


I can sucessfully uploading image to amazon s3 bucket through postman. I am using active storage concepts. As I am buling my front-end using react so how will I store my image to react's state and will send it into params to rails backend.


Solution

  • I use a package called react-dropzone to take away some of the tedious parts of storing files in state, as well as uploading images from react to APIs.

    Here's a very conceptual example of what you'd want to do:

    import React, { Component } from "react";
    import PropTypes from "prop-types";
    import Dropzone from "react-dropzone";
    
    export default class UploadImage extends Component {
      state = {
        files: []
      };
    
      onDrop = (files) => {
        // Get existing files from state
        // (or just the empty array if there are no files in state)
        var currentFiles = this.state.files;
    
        // Push file(s) from function parameters to `currentFiles` array
        const [newFiles] = files;
        currentFiles.push(newFiles);
    
        // Assign files dropped into component into state
        this.setState({
         files: currentFiles
        });
    
        // Attempt to upload the files.
        // If you want to upload after a button click, move the code
        // below to its own function and have it run after button click.
        if (files.length) {
          let formPayLoad = new FormData();
    
          // I'm using "avatar" here for the attribute name of the model that
          // will store the image. Change the first parameter of the 'append' function
          // below to be the name of the attribute name that fits your Rails model.
          formPayLoad.append("avatar", files[files.length - 1]);
    
          // Pass the data to your own defined upload function
          // that makes the call to your API. Make sure you put the
          // formPayLoad in the body of the request.
          this.props.upload(formPayLoad);
        }
      }
    
      render() {
        return (
          <div className="upload-image-component">
            <Dropzone
              onDrop={this.onDrop}
              multiple={true}
            >
              <p>Text that says to upload file.</p>
            </Dropzone>
          </div>
        );
      }
    }
    

    Then have your Rails controller accept the attribute that we're defining in the 'append' function in 'onDrop' above. In my example, I'm using "avatar". Another very conceptual example:

    class UserController < ApiController
    
      # your actions
    
      private
    
      def user_params
        params.permit(
          # all your other params
          :avatar
        )
      end
    
    end