Search code examples
ruby-on-railsmultipartform-datarails-activestoragerails-api

How to upload multiple images and update an entity at the same time. Rails API and JS frontend


I'm trying to make one API call using formData from a React frontend that has multiple images plus strings/booleans etc. to update an entity

I'm using active storage and I am able to attach multiple images to the entity but when I want to update the entity with strings etc. with one API call (ideally). It says this:

param is missing or the value is empty: property

I know that the reason is that my formData is structured like this:

data: {"title": "xxxxxx", "description": "xxxxxx" etc.}, images[]: File, images[]: File etc.

And that I am requiring property as a key and not data:

def property_params
    params.require(:property).permit(:title, :description, :max_guests, :price_per_day, :address,:average_rating, :has_beach_nearby, :has_beds, :has_kitchen, :has_swimming_pool, :has_hdtv,:has_bathtub, :images [])
end

But when I don't do it this way, images is not recognised as it is not permitted so the API doesn't receive it

I am attaching images like this (and it works):

if params[:images].present?
    params[:images].each do |image|
        @property.images.attach(image)
    end
end

Is it possible to upload multiple images and the data using one API call? If not, what do I need to do?

Here is the entire Property controller:

class Api::V1::PropertiesController < ApiController
    before_action :authenticate_user!, only: [:update, :create, :destroy]
            
    def index
       @properties = Property.all
       render json: @properties
    end
            
    def show
       @property = Property.find(params[:id])
       render json: @property
    end
            
    def update
      @property = Property.find(params[:id])
            
      if current_user === @property.user
        if params[:images].present?
           params[:images].each do |image|
              @property.images.attach(image)
           end
        end
            
        @property.update(property_params)
                    
        render json: {
           success: "Successfully updated",property: @property},
           status: 200
      else
        render json: {
           error: "You are not authorized to update this property"}, 
           status: 403
      end
    end
                
    private
    def property_params
       params.require(:property).permit(:title, :description, :max_guests, :price_per_day, :address,:average_rating, :has_beach_nearby, :has_beds, :has_kitchen, :has_swimming_pool, :has_hdtv,:has_bathtub, :images [])
    end

Been stuck for a while so would greatly appreciate any help (new to Rails)


Solution

  • I seem to have solved it by doing this:

        def update
            @property = Property.find(params[:id])
            if current_user === @property.user   
                if params[:images]
                    @property.images.attach(params[:images])
                end
    
                property = @property.update(property_params)
    
                if property 
                    render json: {
                        success: "Successfully updated",
                        property: @property,
                        images: @property.images
                    }, status: 200
                else
                    render json: {
                        error: "Error when updating this property",
                    }, status: 500
                end
            else
                render json: {
                    error: "You are not authorized to update this property"
                }, status: 403
            end
        end
    
        private
    
        def property_params
            json = JSON.parse(params[:data])
            json = ActionController::Parameters.new(json)
            json.permit(
                    :title, :description, :max_guests, 
                    :price_per_day, :address, :average_rating, 
                    :has_beach_nearby, :has_beds, :has_kitchen, 
                    :has_swimming_pool, :has_hdtv, :has_bathtub, images: []
                )
        end
    

    Not sure if this is correct but it seems to work