ruby-on-rails 将Image文件从React上传到Rails服务器

7uhlpewt  于 4个月前  发布在  Ruby
关注(0)|答案(2)|浏览(53)

我正在尝试使用来自React的FormData上传并发送一个简单的图像文件到我的Rails 7 API,因为我读到在上传文件时使用它是正确的。

const handleSubmit = (e) => {
    e.preventDefault();
    
    let formData = new FormData(e.currentTarget);

      
    const data = Object.fromEntries(formData)
    dispatch(createAsset(data)); //this a redux function
    e.currentTarget.reset()
   
  };
<form onSubmit={handleSubmit} className={toggleForm && 'hide-form'}>
   <div>
     <label>Property Title</label>
     <input type="text" id="name" name="name" />
   </div> 
   <div>
   <labal>image upload</labal>
   <input type="file" name="image" />
   </div>
   <button className="btn" type="submit"> create assets</button>
</form>
HTTP request is made

字符串
另一个字段使用除了image_field之外的值访问rails控制台,image_field在rails控制台中显示一个空对象(当我尝试调试时,我在React调试中看到一个image对象)。我想知道我是否做错了什么,为什么image_field向我的Rails应用发送一个空的image对象。

const createAsset = createAsyncThunk('asset/create_asset', async (data) => {
  const response = await fetch(`${baseUrl}assets`, {
    method: 'POST',
    headers: {
      'Content-type': 'application/json',
      Authorization: `Bearer ${token()}`,

    },
    body: JSON.stringify(data),
  }).then((res) => res.json());
  return response;
});


这是rails控制器操作

def create
    @asset = Asset.new(asset_params)

    if @asset.save
      render json: @asset, status: :created
    else
      render json: @asset.errors, status: :unprocessable_entity
    end
  end

def asset_params
      params.require(:asset).permit(:name, :image)
    end


资产模型

class Asset < ApplicationRecord
    has_one_attached :image
      def image_url 
        # Rails.application.routes.url_helpers.rails_blob_path(image, only_path: true)
        Rails.application.routes.url_helpers.url_for(image) if image.attached?

      
    end
    
end


PS:我没有详细说明Rails设置,因为我坚信问题来自React代码

lymnna71

lymnna711#

JS代码中的问题是在发送请求之前如何格式化数据:

'Content-type': 'application/json'

字符串
您正在以JSON格式传输数据,这是处理文件上传时不正确的格式。您应该使用的是这种编码类型:

'Content-type': 'multipart/form-data'


您可以在fetch配置中设置它,但是推荐的方法是通过enctype属性在form元素中声明它:

<form
  className={toggleForm && 'hide-form'}
  enctype="multipart/form-data"
  method="post"
  onSubmit={handleSubmit}
>
  <!-- Elements here -->
</form>


引用MDN docs的话:

**警告:*当使用FormData提交multipart/form-data内容类型的XMLHttpRequestFetch API的POST请求时(例如向服务器上传文件和blob时), 请勿 * 在请求上显式设置Content-Type头。这样做将导致浏览器无法使用边界表达式设置Content-Type头,该表达式将用于分隔请求体中的表单字段。

因此,在发送请求之前,请确保直接传递FormData对象。以下是更新后的获取逻辑:

const createAsset = createAsyncThunk('asset/create_asset', async (data) => {
  const response = await fetch(`${baseUrl}assets`, {
    method: 'POST',
    headers: {
      Authorization: `Bearer ${token()}`,
    },
    body: data, // `FormData` object
  }).then((res) => res.json());
  return response;
});

7hiiyaii

7hiiyaii2#

如果

  • 你使用multipart/form-data作为content-type为您的请求?
  • 你用FormData传递你的身体?
const formData = new FormData()
formData.append('post[name]', name)
formData.append('post[image]', image)

// set `body: formData` in your request

字符串
参考文件:

相关问题