使用 Carrierwave 将图像从 React 上传到 Rails API

Upload image from React to Rails API with Carrierwave

我正在尝试使用载波 gem 将图像从我的 React 应用程序上传到 rails api。到目前为止,我已经尝试了很多东西,并且在互联网上到处寻找都没有找到解决方案。

这是我要发送的请求 request from react

但在 rails 应用程序上,事件参数未被传递

07:57:37 api.1 | Started PATCH "/api/v1/events/8" for 127.0.0.1 at 2018-05-24 07:57:37 -0600 07:57:37 api.1 | Processing by Api::V1::EventsController#update as / 07:57:37 api.1 |
Parameters: {"id"=>"8"} 07:57:37 api.1 | Event Load (4.9ms) SELECT events.* FROM events WHERE events.id = 8 LIMIT 1 07:57:37 api.1 | Completed 401 Unauthorized in 7ms (ActiveRecord: 4.9ms) 07:57:37 api.1 | 07:57:37 api.1 | 07:57:37 api.1 | 07:57:37 api.1 | ActionController::ParameterMissing (param is missing or the value is empty: event): 07:57:37 api.1 | 07:57:37 api.1 | app/controllers/api/v1/events_controller.rb:92:in event_params' 07:57:37 api.1 | app/controllers/api/v1/events_controller.rb:56:in update'

如果我在请求的 body 上使用 JSON.Stringify 发送,它会进入更新功能,但 carrierwave 什么都不做。

我知道 Carrierwave 可以正常工作,因为如果使用 ActiveAdmin 上传图像,它可以正常工作。

这是我创建请求的操作

export const uploadMainImage = (event, eventId) => {

    return (dispatch) => {
        //dispatch({ type: UPLOAD_IMAGE_REQUEST });
        //console.log(window.location);
        let upload = {
            event
        }
        const requestOptions = {
            method: 'PATCH',
            headers: uploadAuthHeader(),
            body: upload
        };
        console.log("request:");
        console.log(requestOptions);
        //window.fetch(window.location.origin + '/api/v1/events/image_upload/' + eventId, requestOptions)
        window.fetch(window.location.origin + '/api/v1/events/' + eventId, requestOptions)
          .then(response => response.json())
          .then(response => {
              dispatch({ type: UPLOAD_IMAGE_SUCCESS, payload: response });
          })
          .catch(error => {
                //console.log(error);
                dispatch({ type: UPLOAD_IMAGE_FAILURE, payload: error })
          })
    };
}

这是 headers:

export function uploadAuthHeader() {
    // return authorization header with jwt token
    let user = JSON.parse(localStorage.getItem('user'));

    if (user && user.auth_token) {
        return { 

            //'Content-Type': 'application/json',
            'Content-Type': 'multipart/form-data',
            'Authorization': 'Bearer ' + user.auth_token 
        };
    } else {
        return {};
    }
}

这里是我处理 react-dropzone

文件选择的地方
readFile(files) {


        const event = {
            imagen: files[0]
        }

        this.props.uploadMainImage(event, this.props.match.params.eventId);

    }

在铁路边,这是我的模型

class Event < ApplicationRecord
  belongs_to :user
  mount_uploader :imagen, ImagenUploader
end

并且 Carrierwave 的上传器未修改默认值。

更新------ 这是我的 event_controller.rb,我正在使用控制器的默认更新方法

module Api
  module V1
    class EventsController < ApiController
      before_action :authenticate_request, only: [:index, :create, :destroy]
      before_action :set_event, only: [:show, :update, :destroy, :image_upload]


      # GET /events
      # Entrego los eventos especificos del usuario loggeado.
      def index
        @events = @current_user.events
        if params[:page]
          @events = @events.page(params[:page]).per(params[:per_page])
          pageCount = @events.total_pages
        else
          #@events = Event.order('fecha ASC')
          pageCount = 1
        end
        render json: { events: @events, meta: { pages: pageCount, records: @events.count } }
      end

      # GET /events/1
      def show
        render json: @event
      end

      # GET /events/upcoming
      def upcoming
        @events = Event.where('fecha >= ?', Date.today).order(:fecha)
        if params[:page]
          @events = @events.page(params[:page]).per(params[:per_page])
          pageCount = @events.total_pages
        else
          #@events = Event.order('fecha ASC')
          pageCount = 1
        end

        render json: { events: @events, meta: { pages: pageCount, records: Event.count } }
      end

      # POST /events
      def create
        @event = Event.new(event_params)
        #@event.imagen = event_params[:imagen][:preview]

        if @event.save
          #@event.imagen = event_params[:imagen][:preview]
          render json: @event, status: :created#, location: @event
        else
          render json: @event.errors, status: :unprocessable_entity
        end
      end

      # PATCH/PUT /events/1
      def update
        if @event.update(event_params)
          render json: @event
        else
          render json: @event.errors, status: :unprocessable_entity
        end
      end


      # DELETE /events/1
      def destroy
        @event.destroy
      end

      private
        # Use callbacks to share common setup or constraints between actions.
        def set_event
          @event = Event.find(params[:id])
        end

        # Only allow a trusted parameter "white list" through.
        def event_params
          params.require(:event).permit!
        end
    end
  end
end

同样来自 Active Admin,event.rb 文件,我只允许 :imagen 字段,当我从 active admin 上传时它工作正常,控制器没有任何变化。

ActiveAdmin.register Event do
# See permitted parameters documentation:
# https://github.com/activeadmin/activeadmin/blob/master/docs/2-resource-customization.md#setting-up-strong-parameters
#
# permit_params :list, :of, :attributes, :on, :model
#
# or
#
# permit_params do
#   permitted = [:permitted, :attributes]
#   permitted << :other if params[:action] == 'create' && current_user.admin?
#   permitted
# end
permit_params :nombre, :user_id, :hora, :fecha, :lugar, :meta, :inicio_inscripcion, 
    :fin_inscripcion, :costo_inscripcion, :pagina_web, :logo, :numero_inicial, 
    :nombre_contacto, :telefono_contacto, :email_contacto, :imagen, :string

end

请帮我弄清楚如何将图像从我的 React 应用程序上传到 Rails API。

第二次更新

这是来自 active_admin

的 POST 请求

于 2018 年 5 月 24 日开始 POST“/admin/events/6”为 ::1 11:54:48 -0600 11:54:48 api.1 | Admin::EventsController#update 处理为 HTML 11:54:48 api.1 |参数:{"utf8"=>"✓", "authenticity_token"=>"9BqST8qDLEJbDlfd6Xs/+YCDMy9qPeCcbOOxbjIGbDoTBRaGAVRU48rqI+E3kD9ORbsiBguS/emJN9JIM+StuQ==", "event"=>{"user_id" =>"1", "nombre"=>"Carrera con Foto", "hora_inicio(1i)"=>"2018", "hora_inicio(2i)"=>"5", "hora_inicio(3i)"=>"24 ", "hora_inicio(4i)"=>"", "hora_inicio(5i)"=>"", "fecha_inicio(1i)"=>"", "fecha_inicio(2i)"=>"", "fecha_inicio(3i)"=>" ", "hora(1i)"=>"2018", "hora(2i)"=>"5", "hora(3i)"=>"24", "hora(4i)"=>"", "hora(5i)" =>"", "fecha(1i)"=>"2018", "fecha(2i)"=>"5", "fecha(3i)"=>"27", "lugar"=>"Villa Olimpica" , "meta"=>"", "inicio_inscripcion(1i)"=>"2018", "inicio_inscripcion(2i)"=>"5", "inicio_inscripcion(3i)"=>"17", "fin_inscripcion(1i)"= >"2018", "fin_inscripcion(2i)"=>"5", "fin_inscripcion(3i)"=>"25", "costo_inscripcion"=>"123", "pagina_web"=>"", "logo"=>"", "numero_inicial"=>"100", "nombre_contacto"=>"Hector Toro", "telefono_contacto"=>"50498761065", "email_contacto"=> "htorohn@gmail.com", "imagen"=>#, @original_filename="IMG_0008.PNG", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"事件[图像]\";文件名=\"IMG_0008.PNG\"\r\nContent-Type:image/png\r\n">},"commit"=>"Update Event" , "id"=>"6"}

更新 3.

我进行了 Bill 建议的更改,但是事件参数仍然没有到达 rails 应用程序。

07:59:02 api.1 |在 2018-05-25 07:59:02 -0600 开始为 127.0.0.1 补丁“/api/v1/events/8” 07:59:02 api.1 | Api::V1::EventsController#update 处理为 / 07:59:02 api.1 |参数:{"id"=>"8"} 07:59:02 api.1 |事件加载 (0.7ms) SELECT events.* FROM events WHERE events.id = 8 LIMIT 1 07:59:02 api.1 |在 8 毫秒内完成 401 未授权(ActiveRecord:0.7 毫秒) 07:59:02 api.1 | 07:59:02 api.1 | 07:59:02 api.1 |
07:59:02 api.1 | ActionController::ParameterMissing(参数缺失或值为空:事件): 07:59:02 api.1 |
07:59:02 api.1 | app/controllers/api/v1/events_controller.rb:95:in event_params' 07:59:02 api.1 | app/controllers/api/v1/events_controller.rb:56:in更新'

enter image description here

因此,查看您的活动管理员允许的参数与您自己的 EventsController 允许的参数,似乎在允许和预期的内容与您从 Javascript 发送的内容方面存在差异。我从您的代码中推断出您的 events table 架构。我无法在本地复制您的代码,因为我没有全部。但这是我认为可行的方法:

您需要像您尝试的那样在正文中传递图像文件数据,但需要使用参数名称 (event[imagen]) 在正文中对其进行编码。试试这个:

export const uploadMainImage = (imageFile, eventId) => {

    let data = new FormData();
    data.append("event[imagen]", imageFile);

    return (dispatch) => {
        //dispatch({ type: UPLOAD_IMAGE_REQUEST });
        //console.log(window.location);
        const requestOptions = {
            method: 'PATCH',
            headers: uploadAuthHeader(),
            body: data
        };
        console.log("request:");
        console.log(requestOptions);
        window.fetch(window.location.origin + '/api/v1/events/' + eventId, requestOptions)
          .then(response => response.json())
          .then(response => {
              dispatch({ type: UPLOAD_IMAGE_SUCCESS, payload: response });
          })
          .catch(error => {
                //console.log(error);
                dispatch({ type: UPLOAD_IMAGE_FAILURE, payload: error })
          })
    };
}


readFile(files) {
    var imageFile = files[0];  // assumes files[0] is from your file form input
    this.props.uploadMainImage(imageFile, this.props.match.params.eventId);
}