Za każdym razem, gdy chcę OPUBLIKOWAĆ tablicę obiektów JSON z jQuery do Railsów, mam ten problem. Jeśli zdefiniuję tablicę, widzę, że jQuery działa poprawnie:
"shared_items"=>"[{\"entity_id\":\"253\",\"position\":1},{\"entity_id\":\"823\",\"position\":2}]"
Ale jeśli po prostu wyślę tablicę jako dane wywołania AJAX, otrzymam:
"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}
Natomiast jeśli wyślę zwykłą tablicę, to działa:
"shared_items"=>["entity_253"]
Dlaczego Railsy zmieniają tablicę na ten dziwny skrót? Jedynym powodem, który przychodzi na myśl, jest to, że Railsy nie mogą poprawnie zrozumieć zawartości, ponieważ nie ma tutaj typu (czy jest sposób, aby ustawić go w wywołaniu jQuery?):
Processing by SharedListsController#create as
Dziękuję Ci!
Aktualizacja:
wysyłam dane jako tablicę, a nie ciąg, a tablica jest tworzona dynamicznie za pomocą .push()
funkcji. Próbowałem $.post
i ten $.ajax
sam wynik.
Content-Type
żądania naapplication/json
, ale zamiast tego wysyłał dane tak, jak zrobiłby to formularz html? Trudno myśleć tak daleko. Railsy działały dobrze, poContent-Type
ustawieniu poprawnej wartości, a wysyłane dane były w poprawnym formacie JSON.contentType: 'application/json'
Trochę stare pytanie, ale dzisiaj sam z tym walczyłem, a oto odpowiedź, na którą wpadłem: uważam, że to trochę wina jQuery, ale robi to tylko to, co jest dla niego naturalne. Mam jednak obejście.
Biorąc pod uwagę następujące wywołanie 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}]} });
Wartości, które opublikuje jQuery, będą wyglądać mniej więcej tak (jeśli spojrzysz na żądanie w swoim Firebug-of-choice), dadzą ci dane formularza, które wyglądają następująco:
shared_items%5B0%5D%5Bentity_id%5D:1 shared_items%5B0%5D%5Bposition%5D:1
Jeśli masz CGI.uncode, który otrzymasz
shared_items[0][entity_id]:1 shared_items[0][position]:1
Wydaje mi się, że dzieje się tak, ponieważ jQuery uważa, że te klucze w twoim JSON są nazwami elementów formularza i że powinno traktować je tak, jakbyś miał pole o nazwie „user [nazwa]”.
Więc przychodzą do twojej aplikacji Railsów, Railsy widzą nawiasy i konstruują hash do przechowywania najbardziej wewnętrznego klucza nazwy pola („1”, które jQuery „pomocnie” dodało).
W każdym razie obejrzałem to zachowanie, konstruując moje wywołanie ajax w następujący sposób;
$.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}])}, } });
Co zmusza jQuery do myślenia, że ten kod JSON jest wartością , którą chcesz przekazać w całości, a nie obiektem JavaScript, który musi przyjąć i zamienić wszystkie klucze w nazwy pól formularza.
Jednak oznacza to, że po stronie Railsów sprawy wyglądają trochę inaczej, ponieważ musisz jawnie zdekodować JSON w params [: data].
Ale jest dobrze:
ActiveSupport::JSON.decode( params[:data] )
TL; DR: Więc rozwiązanie jest takie: w parametrze data w wywołaniu jQuery.ajax () rób to
{"data": JSON.stringify(my_object) }
jawnie, zamiast podawać tablicę JSON do jQuery (gdzie błędnie zgadnie, co chcesz z nią zrobić.źródło
Właśnie natknąłem się na ten problem z Railsami 4. Aby jednoznacznie odpowiedzieć na twoje pytanie ("Dlaczego Railsy zmieniają tablicę na ten dziwny hash?"), Zobacz sekcję 4.1 przewodnika Rails na kontrolerach akcji :
Problem polega na tym, że jQuery formatuje żądanie za pomocą jawnych indeksów tablicowych zamiast pustych nawiasów kwadratowych. Na przykład zamiast wysyłać
shared_items[]=1&shared_items[]=2
, wysyłashared_items[0]=1&shared_items[1]=2
. Szyny widzi indeksów tablicy i interpretuje je jako klawiszy skrótu zamiast indeksów tablicy, zwracając wniosek do dziwnej Ruby hash:{ shared_items: { '0' => '1', '1' => '2' } }
.Jeśli nie masz kontroli nad klientem, możesz rozwiązać ten problem po stronie serwera, konwertując hash na tablicę. Oto jak to zrobiłem:
shared_items = [] params[:shared_items].each { |k, v| shared_items << v }
źródło
Poniższa metoda może być pomocna, jeśli używasz silnych parametrów
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
źródło
Czy rozważałeś zrobienie tego
parsed_json = ActiveSupport::JSON.decode(your_json_string)
? Jeśli wysyłasz rzeczy w inny sposób, możesz użyć.to_json
do serializacji danych.źródło
Czy po prostu próbujesz pobrać ciąg JSON do akcji kontrolera Rails?
Nie jestem pewien, co Railsy robią z hashem, ale możesz obejść problem i mieć więcej szczęścia, tworząc obiekt Javascript / JSON (w przeciwieństwie do ciągu JSON) i wysyłając go jako parametr danych dla swojego Ajax połączenie.
myData = { "shared_items": [ { "entity_id": "253", "position": 1 }, { "entity_id": "823", "position": 2 } ] };
Jeśli chcesz wysłać to przez Ajax, zrób coś takiego:
$.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); } });
Zauważ, że z powyższym fragmentem Ajaxa, jQuery dokona inteligentnego odgadnięcia typu dataType, chociaż zwykle dobrze jest go wyraźnie określić.
Tak czy inaczej, w akcji kontrolera możesz pobrać obiekt JSON, który przekazałeś z hashem params, tj
params[:shared_items]
Np. Ta czynność wypluje z powrotem twój obiekt json:
def reply_in_json @shared = params[:shared_items] render :json => @shared end
źródło
Użyj klejnotu rack-jquery-params (zastrzeżenie: jestem autorem). Rozwiązuje problem z tablicami, które stają się skrótami z kluczami całkowitymi.
źródło