使用 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);
}
我正在尝试使用载波 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) SELECTevents
.* FROMevents
WHEREevents
.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:inevent_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);
}