Каждый раз, когда я хочу отправить массив объектов JSON с помощью jQuery в Rails, у меня возникает эта проблема. Если я структурирую массив, я вижу, что jQuery выполняет свою работу правильно:
"shared_items"=>"[{\"entity_id\":\"253\",\"position\":1},{\"entity_id\":\"823\",\"position\":2}]"
Но если я просто отправлю массив как данные вызова AJAX, я получу:
"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}
Если я просто отправлю простой массив, он работает:
"shared_items"=>["entity_253"]
Почему Rails меняет массив на этот странный хеш? Единственная причина, которая приходит на ум, заключается в том, что Rails не может правильно понять содержимое, потому что здесь нет типа (есть ли способ установить его в вызове jQuery?):
Processing by SharedListsController#create as
Спасибо!
Обновление:
я отправляю данные в виде массива, а не строки, и массив создается динамически с помощью .push()
функции. Пробовал с $.post
и $.ajax
, результат тот же.
Content-Type
запросapplication/json
, а вместо этого отправлял данные в виде html-формы? Трудно вспомнить так далеко. Rails работал нормально, после того, какContent-Type
было установлено правильное значение, и отправляемые данные были действительным JSON.contentType: 'application/json'
Немного старый вопрос, но я сам боролся с этим сегодня, и вот ответ, который я придумал: я считаю, что это небольшая ошибка jQuery, но он делает только то, что для него естественно. Однако у меня есть обходной путь.
Учитывая следующий вызов jQuery ajax:
$.ajax({ type : "POST", url : 'http://localhost:3001/plugin/bulk_import/', dataType: 'json', data : {"shared_items": [{"entity_id":"253","position":1},{"entity_id":"823","position":2}]} });
Значения, которые публикует jQuery, будут выглядеть примерно так (если вы посмотрите на Request в вашем Firebug-of-choice), вы получите данные формы, которые выглядят так:
shared_items%5B0%5D%5Bentity_id%5D:1 shared_items%5B0%5D%5Bposition%5D:1
Если вы CGI.unencode, вы получите
shared_items[0][entity_id]:1 shared_items[0][position]:1
Я считаю, что это связано с тем, что jQuery считает, что эти ключи в вашем JSON являются именами элементов формы и что он должен обрабатывать их, как если бы у вас было поле с именем «user [name]».
Итак, они входят в ваше приложение Rails, Rails видит скобки и создает хеш для хранения самого внутреннего ключа имени поля («1», которую jQuery «услужливо» добавил).
Во всяком случае, я обошел это поведение, построив свой вызов ajax следующим образом;
$.ajax({ type : "POST", url : 'http://localhost:3001/plugin/bulk_import/', dataType: 'json', data : {"data": JSON.stringify({"shared_items": [{"entity_id":"253","position":1},{"entity_id":"823","position":2}])}, } });
Это заставляет jQuery думать, что этот JSON - это значение, которое вы хотите передать целиком, а не объект Javascript, который он должен принять, и превратить все ключи в имена полей формы.
Однако это означает, что на стороне Rails все немного иначе, потому что вам нужно явно декодировать JSON в params [: data].
Но это нормально:
ActiveSupport::JSON.decode( params[:data] )
TL; DR: Итак, решение: в параметре данных для вашего вызова jQuery.ajax () сделайте
{"data": JSON.stringify(my_object) }
явно, вместо того, чтобы загружать массив JSON в jQuery (где он неправильно угадывает, что вы хотите с ним делать.источник
Я только что столкнулся с этой проблемой с Rails 4. Чтобы явно ответить на ваш вопрос («Почему Rails меняет массив на этот странный хеш?»), См. Раздел 4.1 руководства Rails по контроллерам действий :
Проблема в том, что jQuery форматирует запрос с помощью явных индексов массива, а не с помощью пустых квадратных скобок. Так, например, вместо отправки
shared_items[]=1&shared_items[]=2
он отправляетshared_items[0]=1&shared_items[1]=2
. Rails видит индексы массива и интерпретирует их как хеш-ключи, а не индексы массива, превращая запрос в странный хеш Ruby:{ shared_items: { '0' => '1', '1' => '2' } }
.Если у вас нет контроля над клиентом, вы можете решить эту проблему на стороне сервера, преобразовав хэш в массив. Вот как я это сделал:
shared_items = [] params[:shared_items].each { |k, v| shared_items << v }
источник
следующий метод может быть полезен, если вы используете строгие параметры
def safe_params values = params.require(:shared_items) values = items.values if items.keys.first == '0' ActionController::Parameters.new(shared_items: values).permit(shared_items: [:entity_id, :position]).require(:shared_items) end
источник
Вы думали сделать
parsed_json = ActiveSupport::JSON.decode(your_json_string)
? Если вы отправляете материал другим способом, вы можете использовать его.to_json
для сериализации данных.источник
Вы просто пытаетесь вставить строку JSON в действие контроллера Rails?
Я не уверен, что Rails делает с хешем, но вы можете обойти проблему и получить больше удачи, создав объект Javascript / JSON (в отличие от строки JSON) и отправив его как параметр данных для вашего Ajax вызов.
myData = { "shared_items": [ { "entity_id": "253", "position": 1 }, { "entity_id": "823", "position": 2 } ] };
Если вы хотите отправить это через ajax, сделайте что-то вроде этого:
$.ajax({ type: "POST", url: "my_url", // be sure to set this in your routes.rb data: myData, success: function(data) { console.log("success. data:"); console.log(data); } });
Обратите внимание на приведенный выше фрагмент ajax, jQuery сделает разумное предположение о типе данных, хотя обычно лучше указать его явно.
В любом случае, в действии вашего контроллера вы можете получить объект JSON, который вы передали с хешем params, т.е.
params[:shared_items]
Например, это действие вернет вам ваш json-объект:
def reply_in_json @shared = params[:shared_items] render :json => @shared end
источник
Используйте гем rack-jquery-params (отказ от ответственности: я являюсь автором). Он устраняет проблему превращения массивов в хэши с целочисленными ключами.
источник