Rails UJS发送FormData时嵌套参数为索引对象而非数组的方案咨询
我正在尝试使用formData与Rails ujs向Rails服务器发送数据,前端JS代码如下:
Rails.ajax({ url: "/reset-cart", type: "post", data: new FormData(this.formTarget), success: function(data) { console.log('success') }, error: function(data) { console.log('error') } })
Object.fromEntries(new FormData(this.formTarget)) 返回结果为:
{ "cart[cart_items_attributes][0][product_id]": "210", "cart[cart_items_attributes][0][quantity]": "4", "cart[cart_items_attributes][1][product_id]": "12", "cart[cart_items_attributes][1][quantity]": "4" }
在Rails控制器中,接收到的数据格式如下:
#<ActionController::Parameters {"cart"=>{"cart_items_attributes"=>{"0"=>{"product_id"=>"210", "quantity"=>"4"}, "1"=>{"product_id"=>"12", "quantity"=>"4"}}}, "controller"=>"carts", "action"=>"reset"} permitted: false>
期望的数据格式为cart_items_attributes是哈希构成的数组:
{ "cart"=> { "cart_items_attributes"=> [ { "product_id"=>"210", "quantity"=>"4" },{ "product_id"=>"12", "quantity"=>"4" } ] } }
核心疑问:是否可以通过调整Rails.ajax函数中的数据发送方式实现该效果,还是必须在控制器中编写自定义方法,对params哈希中接收的数据进行重新格式化?
你完全不需要编写复杂的自定义参数格式化逻辑,几种处理方式都非常简单,甚至绝大多数场景下你不需要做任何调整就能正常使用:
现有参数格式可直接兼容Rails原生嵌套属性逻辑
Rails的accepts_nested_attributes_for本身就原生支持整数键的哈希格式参数,这是框架刻意设计的行为——为了适配表单生成的带索引的嵌套字段、支持不连续索引、嵌套记录删除等场景。你当前收到的参数,只要按常规写法配置strong parameters:def cart_params params.require(:cart).permit(cart_items_attributes: [:product_id, :quantity]) end直接传入模型的
create/update方法就能正常工作,和你期望的数组格式效果完全一致,不需要做任何转换。前端调整可直接让Rails解析为数组
如果你确实需要参数直接解析为数组格式,不需要改Rails.ajax的调用逻辑,只需要调整FormData内的字段名:把cart_items_attributes后的数字索引替换为空的[]即可,对应字段名格式为:cart[cart_items_attributes][][product_id] cart[cart_items_attributes][][quantity] cart[cart_items_attributes][][product_id] cart[cart_items_attributes][][quantity]Rails的参数解析器遇到空方括号的键时,会自动按FormData的字段顺序组装成对象数组。注意这种方式依赖字段的append顺序,如果存在嵌套记录删除、索引不连续的场景,不建议用这种写法。
后端转换仅需一行代码
如果你保留当前的传参方式,又确实需要拿到数组格式,不需要写复杂的遍历格式化逻辑,直接取哈希的values即可:cart_items_array = params[:cart][:cart_items_attributes].values就能直接得到你需要的由商品项哈希构成的数组。
内容的提问来源于stack exchange,提问作者David Geismar

