Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/ruby-on-rails/62.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ruby on rails Rails API,如何从react native接收使用FormData发送的照片_Ruby On Rails_Reactjs_React Native - Fatal编程技术网

Ruby on rails Rails API,如何从react native接收使用FormData发送的照片

Ruby on rails Rails API,如何从react native接收使用FormData发送的照片,ruby-on-rails,reactjs,react-native,Ruby On Rails,Reactjs,React Native,我使用rails作为后端,react native作为前端,我尝试在react native中使用formdata上传一张照片,并在rails中使用活动存储来保存它。 使用一个型号名称Room.rb,并附上一张照片 Room.rb class Room < ApplicationRecord has_one_attached :photo end 我在@room.save中发现一个错误,说“TypeError-hash key“uri”不是一个符号:” 我的期望是,当我从手机(客户端

我使用rails作为后端,react native作为前端,我尝试在react native中使用formdata上传一张照片,并在rails中使用活动存储来保存它。 使用一个型号名称Room.rb,并附上一张照片

Room.rb

class Room < ApplicationRecord
  has_one_attached :photo
end
我在@room.save中发现一个错误,说“TypeError-hash key“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;
import React,{useState}来自“React”;
从“expo常量”导入常量;
进口{
活动指示器,
按钮
剪贴板,
形象,,
分享,
状态栏,
样式表,
文本,
可触摸不透明度,
看法
}从“反应本机”;
从“世博会图像采集器”导入*作为图像采集器;
从“expo Permissions”导入*作为权限;
const RoomUploadPhoto=({uriPhoto,onPhotoChange})=>{
const[upload,setUploading]=useState(false);
常量renderUploadingIndicator=()=>{
如果(上传){
返回;
}
};
常量askPermission=async(类型,故障消息)=>{
const{status,permissions}=wait permissions.askAsync(类型);
如果(状态==‘拒绝’){
警报(故障信息);
}
};
常量handleImagePicked=(pickerResult)=>{
onPhotoChange(pickerResult.uri);
};
const takePhoto=async()=>{
等待askPermission(
摄像机,
“我们需要相机许可才能拍照……”
);
等待askPermission(
许可证。摄像机滚动,
“我们需要相机卷许可才能读取您手机上的图片…”
);
const pickerResult=等待ImagePicker.launchCameraAsync({
允许编辑:对,
相位:[4,3],
});
手工拾取(pickerResult);
};
const pickImage=async()=>{
等待askPermission(
许可证。摄像机滚动,
“我们需要相机卷许可才能读取您手机上的图片…”
);
const pickerResult=等待ImagePicker.launchImageLibraryAsync({
允许编辑:对,
相位:[4,3],
});
手动拾取图像(pickerResult);
};
const renderControls=()=>{
如果(!上传){
返回(
);
}
};
返回(
上传照片
{renderUploadingIndicator()}
{renderControls()}
);
};
const styles=StyleSheet.create({
viewSatu:{
利润率:8
}
});
导出默认的RoomUploadPhoto;

确保将
文件
对象或
base64
内容发布到后端。您的
photo
目前只是一个json对象,包含文件路径和名称

请从您的
房间参数
中删除
照片
参数

def房间参数
参数要求(:房间)。许可证(
:房间名称
)
结束
并在创建
房间时附上您的
照片

def创建
@房间=房间。新建(房间参数)
@房间。附加参数[:照片]
...

你能上传你的react原生代码提交表单数据吗?@yash谢谢你的回答,我添加了上传照片的react原生代码(见更新2),请告诉我你是否对react原生部分进行了更正,因为这是我第一次尝试上传照片,我可以看到你的请求不正确。你的照片应该是一个文件对象而不是json。哦,好的,你能给我你的更正吗,谢谢你通过文件输入对话框上传文件吗?最后我找到了解决方案,你上面的回答对我帮助很大,这里也对我有帮助
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' });
  }
};
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;