【发布时间】:2020-11-20 12:46:35
【问题描述】:
我使用 rails 作为后端并将 react native 作为前端,我正在尝试使用 react native 中的 formdata 上传一张照片,并使用 rails 中的活动存储来保存它。 使用一个模型名称 Room.rb 和 has_one_attached :photo。
房间.rb
class Room < ApplicationRecord
has_one_attached :photo
end
这里是rails收到的参数,有两个(房间名和照片)
{
"room_name"=>"Guest Room",
"photo"=>
<ActionController::Parameters {
"uri"=>"file:///Users/MyName/Library/Developer/CoreSimulator/Devices/guest_room.jpg",
"name"=>"guest_room.jpg",
"type"=>"image/jpg"
} permitted: true >
}
room_controller.rb 保存和接收文件如下
def create
@room = Room.create(room_params)
if @room.save
render json: RoomSerializer.new(@room).serializable_hash, status: :created
else
render json: { errors: @room.errors }, status: :unprocessable_entity
end
end
我在@room.save 中收到错误消息,提示“TypeError - 哈希键“uri”不是符号:' 我期望在我从手机(客户端)中选择图像并按下保存按钮后,它会自动下载图像,这也是我使用 react native 的 FormData 发送的原因。
更新 2:
这是上传照片的 react native 的一部分,
const preparePhoto = (uriPhoto) => {
// ImagePicker saves the taken photo to disk and returns a local URI to it
const localUri = uriPhoto;
const name = localUri.split('/').pop();
// Infer the type of the image
const match = /\.(\w+)$/.exec(name);
const type = match ? `image/${match[1]}` : `image`;
return [name, type];
};
const createRoom = dispatch => async ({ room_name, uriPhoto }) => {
const [name, type] = preparePhoto(uriPhoto);
const photo = { uri: uriPhoto, name, type };
const room = { room_name, photo };
const formData = new FormData();
formData.append('room', JSON.stringify(room));
const config = { headers: {
Accept: 'application/json',
'Content-Type': 'multipart/form-data',
} };
try {
const response = await serverApi.post('/rooms', formData, config);
dispatch({ type: 'clear_error' });
} catch (err) {
console.log('error: ', err);
dispatch({ type: 'add_error', payload: 'Sorry we have problem' });
}
};
更新 3:
选择图像并将其发送到上下文的源代码
import React, { useState } from 'react';
import Constants from 'expo-constants';
import {
ActivityIndicator,
Button,
Clipboard,
Image,
Share,
StatusBar,
StyleSheet,
Text,
TouchableOpacity,
View,
} from 'react-native';
import * as ImagePicker from 'expo-image-picker';
import * as Permissions from 'expo-permissions';
const RoomUploadPhoto = ({ uriPhoto, onPhotoChange }) => {
const [uploading, setUploading] = useState(false);
const renderUploadingIndicator = () => {
if (uploading) {
return <ActivityIndicator animating size="large" />;
}
};
const askPermission = async (type, failureMessage) => {
const { status, permissions } = await Permissions.askAsync(type);
if (status === 'denied') {
alert(failureMessage);
}
};
const handleImagePicked = (pickerResult) => {
onPhotoChange(pickerResult.uri);
};
const takePhoto = async () => {
await askPermission(
Permissions.CAMERA,
'We need the camera permission to take a picture...'
);
await askPermission(
Permissions.CAMERA_ROLL,
'We need the camera-roll permission to read pictures from your phone...'
);
const pickerResult = await ImagePicker.launchCameraAsync({
allowsEditing: true,
aspect: [4, 3],
});
handleImagePicked(pickerResult);
};
const pickImage = async () => {
await askPermission(
Permissions.CAMERA_ROLL,
'We need the camera-roll permission to read pictures from your phone...'
);
const pickerResult = await ImagePicker.launchImageLibraryAsync({
allowsEditing: true,
aspect: [4, 3],
});
handleImagePicked(pickerResult);
};
const renderControls = () => {
if (!uploading) {
return (
<View>
<View style={styles.viewSatu}>
<Button
onPress={pickImage}
title="Pick an image from camera roll"
/>
</View>
<View style={styles.viewSatu}>
<Button onPress={takePhoto} title="Take a photo" />
</View>
</View>
);
}
};
return (
<React.Fragment>
<Text>upload photo</Text>
{renderUploadingIndicator()}
{renderControls()}
</React.Fragment>
);
};
const styles = StyleSheet.create({
viewSatu: {
marginVertical: 8
}
});
export default RoomUploadPhoto;
【问题讨论】:
-
可以上传你的 react 原生代码提交表单数据吗?
-
@yash 感谢您的回答,我添加了上传照片的反应原生代码(请参阅更新 2),如果您对反应原生部分有更正,请告诉我,因为这是我第一次尝试上传照片
-
我可以看到您的请求不正确。您的照片应该是文件对象而不是 json。
-
哦好的,能不能给我指正一下,谢谢
-
您是否通过文件输入对话框上传文件?
标签: ruby-on-rails reactjs react-native