Первое, что вам нужно понять, чтобы решить эту проблему, это то, что вы в настоящее время не отправляете JSON.JQuery сериализует данные как application/x-www-form-urlencoded
, используя функцию param()
, и отправляет (фактически отправляет экранированную версию этого):
cart[0][qty]=1&cart[0][product][name]=baseball&cart[1][qty]=3&cart[1][product][name]=soccer
Документация дляparam()
имеет следующую пару примечаний:
Примечание. Поскольку некоторые платформы имеют ограниченную возможность разбора сериализованных массивов, разработчики должны соблюдать осторожность при передаче аргумента obj, содержащего объекты или массивы, вложенные в другой массив..
и
Примечание. Поскольку не существует универсально согласованной спецификации для строк параметров, невозможно кодировать сложные структуры данных с использованием этого метода таким образом,это идеально работает на всех языках, поддерживающих такой ввод.Вместо этого используйте формат JSON в качестве альтернативы для кодирования сложных данных.
Это проблема, с которой вы столкнулись.Sinatra пытается проанализировать данные, закодированные в форме, в структуру данных 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 и, при необходимости, заполнила хэш параметров.
Один из способов сделать это - использовать модуль Rack contrib PostBodyContentTypeParser
.Просто добавьте в свое приложение следующее (сначала вам нужно будет установить гем rack-contrib
):
require 'rack/contrib/post_body_content_type_parser'
use Rack::PostBodyContentTypeParser
Теперь любой запрос POST или PUT, имеющий тип содержимого JSON, будет проанализирован, и содержимое добавлено вхэш параметров.Однако в текущей выпущенной версии нет способа конвертировать ключи в символы (в мастере есть изменение, позволяющее это сделать, но оно еще не выпущено), поэтому будет производиться что-то вроде:
{
"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
, но дает данные в форме, которую вы ищете.