【问题标题】:Upload image from React to Rails API with Carrierwave使用 Carrierwave 将图像从 React 上传到 Rails API
【发布时间】:2018-05-24 14:09:54
【问题描述】:

我正在尝试使用carrierwave gem 将图像从我的react 应用上传到rails api。到目前为止,我已经尝试了很多方法并在互联网上到处寻找,但没有找到解决方案。

这是我发送的请求 request from react

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

07:57:37 api.1 |在 127.0.0.1 开始 PATCH "/api/v1/events/8" 2018-05-24 07:57:37 -0600 07:57:37 api.1 |处理者 Api::V1::EventsController#update as / 07:57:37 api.1 |
参数:{"id"=>"8"} 07:57:37 api.1 |事件加载 (4.9ms) 选择 events.* FROM events WHERE events.id = 8 限制 1 07:57:37 api.1 | 7ms 内完成 401 Unauthorized (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(参数丢失或 值为空:事件):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'

如果我在请求正文中使用 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 })
          })
    };
}

这是标题:

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 的 Uploader 没有从默认值修改。

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

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 字段,当我从活动管理员上传时,它可以正常工作,无需对控制器进行任何更改。

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 日 11:54:48 -0600 开始为 ::1 发布 POST "/admin/events/6" 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"=>"别墅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_initial"=>"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;名称=\“事件[图像]\”; filename=\"IMG_0008.PNG\"\r\nContent-Type: image/png\r\n">}, "commit"=>"更新事件", "id"=>"6"}

更新 3。

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

07:59:02 api.1 |在 2018-05-25 07:59:02 -0600 为 127.0.0.1 开始 PATCH "/api/v1/events/8" 07:59:02 api.1 | Api::V1::EventsController#update as / 处理 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 | 8ms 内完成 401 Unauthorized (ActiveRecord: 0.7ms) 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:inupdate'

enter image description here

【问题讨论】:

  • 您可以发布您的 API 控制器的代码吗?在您的反应代码中,您在请求正文中传递事件,但您的控制器似乎希望它作为请求参数。向我们展示您的 events.rb 活动管理文件也可能有助于比较。
  • 嗨,比尔,感谢您的评论,我已将您提到的文件添加到帖子中。
  • 所以,我得到了一张更好的照片。您可以在通过活动管理员更新事件时发布#update 请求日志吗?我已经有了一个理论。我现在要回答,但请尽可能发布该请求日志。我想我们肯定可以从中弄清楚。
  • 我根据 active_admin 的请求更新了帖子

标签: ruby-on-rails ruby reactjs api carrierwave


【解决方案1】:

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

您需要在正文中传递图像文件数据,就像您尝试的那样,但它需要在正文中使用参数名称 (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);
}

【讨论】:

  • @HectorToro,对不起,我在考虑 jQuery $.ajax。我已经更新了我的答案。如果有帮助,请告诉我。
  • 伙计,非常感谢,最新的解决方案效果很好,只需要在标题中注释这一行 - 'Content-Type': 'multipart/form-data' - 如果是 Content-类型存在,请求未正确解析。
猜你喜欢
  • 1970-01-01
  • 2018-04-18
  • 2012-07-08
  • 2019-06-09
  • 1970-01-01
  • 2014-02-12
  • 1970-01-01
  • 2013-06-27
  • 1970-01-01
相关资源
最近更新 更多