要解决此问题,您首先需要了解的是您当前不发送 JSON。 JQuery 正在将数据序列化为application/x-www-form-urlencoded,使用param() function,并且正在发送(它实际上是发送此转义版本):
cart[0][qty]=1&cart[0][product][name]=baseball&cart[1][qty]=3&cart[1][product][name]=soccer
param() 的文档有以下一对注释:
注意:由于某些框架解析序列化数组的能力有限,因此开发人员在传递包含嵌套在另一个数组中的对象或数组的 obj 参数时应谨慎。
和
注意:因为没有普遍认可的参数字符串规范,所以不可能使用这种方法以一种在所有支持这种输入的语言中都能理想地工作的方式对复杂的数据结构进行编码。使用 JSON 格式替代编码复杂数据。
这是您面临的问题。 Sinatra 尝试将 form-urlencoded 数据解析为 Ruby 数据结构,但它期望使用不同的格式。它使用Rack::Utils.parse_nested_query 生成您从该查询字符串中看到的参数。
正如 jQuery 文档所建议的,解决方案是将数据作为 JSON 发送。这将确保浏览器和服务器之间的数据结构不会被破坏。
第一步是让浏览器发送 JSON。您可以使用 post() 函数的其他形式来执行此操作,指定内容类型并将数据转换为 JSON 字符串:
$.post({url: "/endpoint", data: JSON.stringify(payload), contentType: "application/json", success: submit});
默认情况下,Sinatra 将忽略任何内容类型为 JSON 的请求,并将处理留给您,因此解决方案的另一半是让 Sinatra 解析 JSON,并可选择填充 params 哈希。
使用 Rack contrib 模块PostBodyContentTypeParser 的一种方法。只需将以下内容添加到您的应用中(您需要先安装 rack-contrib gem):
require 'rack/contrib/post_body_content_type_parser'
use Rack::PostBodyContentTypeParser
现在将解析任何具有 JSON 内容类型的 POST 或 PUT 请求,并将内容添加到 params 哈希中。但是,当前发布的版本没有将键转换为符号的方法(master 中进行了更改以允许这样做,但尚未发布),因此它会产生如下内容:
{
"cart"=>[
{"qty"=>1, "product"=>{"name"=>"baseball"}},
{"qty"=>3, "product"=>{"name"=>"soccer"}}
]
}
如果您想获得符号化的键,您必须“手动”完成。在您的路线中,您可以添加:
request.body.rewind # Just in case some middleware has already read it
data = JSON.parse(request.body.read, symbolize_names: true)
(如果需要,您可以将其添加到 before 过滤器中,只需添加内容类型是否为 JSON 的检查)。
这不会将数据添加到 params 哈希中,但会以您正在寻找的形式为您提供数据。