如何同时上传多张图片和更新一个实体 Rails API 和 JS 前端

问题描述

我正在尝试使用来自 React 前端的 formData 进行一个 API 调用,该前端具有多个图像以及字符串/布尔值等,以更新实体

我正在使用主动存储,并且能够将多个图像附加到实体,但是当我想通过一个 API 调用(理想情况下)使用字符串等更新实体时。它是这样说的:

参数缺失或值为空:属性

我知道原因是我的 formData 的结构是这样的:

data: {"title": "xxxxxx","description": "xxxxxx" etc.},images[]: File,images[]: File etc.

而且我需要属性作为键而不是数据:

def property_params
    params.require(:property).permit(:title,:description,:max_guests,:price_per_day,:address,:average_rating,:has_beach_nearby,:has_beds,:has_kitchen,:has_swimming_pool,:has_hdtv,:has_bathtub,:images [])
end

但是当我不这样做时,图像无法识别,因为这是不允许的,因此 API 不会接收它

我正在附上这样的图像(并且有效):

if params[:images].present?
    params[:images].each do |image|
        @property.images.attach(image)
    end
end

是否可以使用一次 API 调用上传多张图片和数据?如果没有,我需要做什么?

这是整个属性控制器:

class Api::V1::PropertiesController < ApiController
    before_action :authenticate_user!,only: [:update,:create,:destroy]
            
    def index
       @properties = Property.all
       render json: @properties
    end
            
    def show
       @property = Property.find(params[:id])
       render json: @property
    end
            
    def update
      @property = Property.find(params[:id])
            
      if current_user === @property.user
        if params[:images].present?
           params[:images].each do |image|
              @property.images.attach(image)
           end
        end
            
        @property.update(property_params)
                    
        render json: {
           success: "Successfully updated",property: @property},status: 200
      else
        render json: {
           error: "You are not authorized to update this property"},status: 403
      end
    end
                
    private
    def property_params
       params.require(:property).permit(:title,:images [])
    end

被卡住了一段时间,所以非常感谢任何帮助(Rails 新手)

解决方法

Rack 使用方括号在 formdata 中传递哈希值:

irb(main):005:0> Rack::Utils.parse_nested_query("property[title]=foo&property[description]=bar")
=> {"property"=>{"title"=>"foo","description"=>"bar"}}

可以使用空括号传递数组:

irb(main):008:0> Rack::Utils.parse_nested_query("property[foo][]=a&property[foo]&[]=property[foo][]=c")
=> {"property"=>{"foo"=>nil}}

对于多部分表单数据,您通常会使用表单(可见表单或虚拟表单)并在输入上设置 name 属性:

<form action="/properties" method="post" multipart>
  <input name="property[images][]" type="file" />
  <input name="property[images][]" type="file" />
</form>

Rack 会将请求正文的各个部分拼接在一起并创建单个参数哈希。

您也有语法错误:

# Use sensible line lengths and this won't happen as often...
params.require(:property)
      .permit(
         :title,:description,:max_guests,:price_per_day,:address,:average_rating,:has_beach_nearby,:has_beds,:has_kitchen,:has_swimming_pool,:has_hdtv,:has_bathtub,images: []
      )

要将数组或嵌套参数列入白名单,您需要使用哈希作为要允许的最后一个参数。 images: [] 将允许包含 ActionDispatch::UploadedFile 的允许标量数组。

如果您想将包含嵌套和平面参数的非常规参数列入白名单,您需要更有创意。要记住的关键是 ActionController::Parameters 是一个类似散列的对象,您可以像散列一样操作它:

def property_params   
  params.require(:data)
        .permit(
           :title,:has_bathtub
        ).merge(
           # fetch is like require but does not raise if the key is not present
           images: params.fetch(:images,[]) 
        )
end

使用 ActiveStorage,您实际上不会need to manually attach the files

,

我似乎通过这样做解决了它:

    def update
        @property = Property.find(params[:id])
        if current_user === @property.user   
            if params[:images]
                @property.images.attach(params[:images])
            end

            property = @property.update(property_params)

            if property 
                render json: {
                    success: "Successfully updated",property: @property,images: @property.images
                },status: 200
            else
                render json: {
                    error: "Error when updating this property",},status: 500
            end
        else
            render json: {
                error: "You are not authorized to update this property"
            },status: 403
        end
    end

    private

    def property_params
        json = JSON.parse(params[:data])
        json = ActionController::Parameters.new(json)
        json.permit(
                :title,images: []
            )
    end

不确定这是否正确,但似乎有效

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...