programing

Rails가 jQuery에서 JSON을 올바르게 디코딩하지 않음 (정수 키가있는 해시 배열)

nasanasas 2020. 9. 7. 08:15
반응형

Rails가 jQuery에서 JSON을 올바르게 디코딩하지 않음 (정수 키가있는 해시 배열)


jQuery를 사용하여 JSON 객체 배열을 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, 동일한 결과를 시도했습니다 .


누군가이 문제를 발견하고 더 나은 솔루션을 원하는 경우 .ajax 호출에서 "contentType : 'application / json'"옵션을 지정하고 Rails가 JSON 객체를 all- 정수 키가있는 해시로 분해하지 않고 올바르게 구문 분석하도록 할 수 있습니다. 문자열 값.

요약하면 내 문제는 다음과 같습니다.

$.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}]}
});

Rails에서 다음과 같이 구문 분석했습니다.

Parameters: {"shared_items"=>{"0"=>{"entity_id"=>"253", "position"=>"1"}, "1"=>{"entity_id"=>"823", "position"=>"2"}}}

반면 (참고 : 이제 자바 스크립트 객체를 문자열 화하고 콘텐츠 유형을 지정하고 있으므로 레일은 문자열을 구문 분석하는 방법을 알게됩니다) :

$.ajax({
  type : "POST",
  url :  'http://localhost:3001/plugin/bulk_import/',
  dataType: 'json',
  contentType: 'application/json',
  data : JSON.stringify({"shared_items": [{"entity_id":"253","position":1}, {"entity_id":"823","position":2}]})
});

Rails에서 멋진 객체가 생성됩니다.

Parameters: {"shared_items"=>[{"entity_id"=>"253", "position"=>1}, {"entity_id"=>"823", "position"=>2}]}

이것은 Ruby 1.9.3의 Rails 3에서 저에게 효과적입니다.


약간 오래된 질문이지만 오늘 직접이 문제를 해결했습니다. 여기에 제가 생각해 낸 답이 있습니다. 이것은 약간 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}]}

});

The values jQuery will post will look something like this (if you look at the Request in your Firebug-of-choice) will give you form data that looks like:

shared_items%5B0%5D%5Bentity_id%5D:1
shared_items%5B0%5D%5Bposition%5D:1

If you CGI.unencode that you'll get

shared_items[0][entity_id]:1
shared_items[0][position]:1

I believe this is because jQuery thinks that those keys in your JSON are form element names, and that it should treat them as if you had a field named "user[name]".

So they come into your Rails app, Rails sees the brackets, and constructs a hash to hold the innermost key of the field name (the "1" that jQuery "helpfully" added).

Anyway, I got around this behavior by constructing my ajax call the following way;

$.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}])},
  }
});

Which forces jQuery to think that this JSON is a value that you want to pass, entirely, and not a Javascript object it must take and turn all the keys into form field names.

However, that means things are a little different on the Rails side, because you need to explicitly decode the JSON in params[:data].

But that's OK:

ActiveSupport::JSON.decode( params[:data] )

TL;DR: So, the solution is: in the data parameter to your jQuery.ajax() call, do {"data": JSON.stringify(my_object) } explicitly, instead of feeding the JSON array into jQuery (where it guesses wrongly what you want to do with it.


I just ran into this issue with Rails 4. To explicitly answer your question ("Why is Rails changing the array to that strange hash?"), see section 4.1 of the Rails guide on Action Controllers:

To send an array of values, append an empty pair of square brackets "[]" to the key name.

The problem is, jQuery formats the request with explicit array indices, rather than with empty square brackets. So, for example, instead of sending shared_items[]=1&shared_items[]=2, it sends shared_items[0]=1&shared_items[1]=2. Rails sees the array indices and interprets them as hash keys rather than array indices, turning the request into a weird Ruby hash: { shared_items: { '0' => '1', '1' => '2' } }.

If you don't have control of the client, you can fix this problem on the server side by converting the hash to an array. Here's how I did it:

shared_items = []
params[:shared_items].each { |k, v|
  shared_items << v
}

following method could be helpful if you use strong parameters

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

Have you considered doing parsed_json = ActiveSupport::JSON.decode(your_json_string)? If you're sending stuff the other way about you can use .to_json to serialise the data.


Are you just trying to get the JSON string into a Rails controller action?

I'm not sure what Rails is doing with the hash, but you might get around the problem and have more luck by creating a Javascript/JSON object (as opposed to a JSON string) and sending that through as the data parameter for your Ajax call.

myData = {
  "shared_items":
    [
        {
            "entity_id": "253",
            "position": 1
        }, 
        {
            "entity_id": "823",
            "position": 2
        }
    ]
  };

If you wanted to send this via ajax then you would do something like this:

$.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);
    }
});

Note with the ajax snippet above, jQuery will make an intelligent guess on the dataType, although it's usually good to specify it explicitly.

Either way, in your controller action, you can get the JSON object you passed with the params hash, i.e.

params[:shared_items]

E.g. this action will spit your json object back at you:

def reply_in_json
  @shared = params[:shared_items]

  render :json => @shared
end

Use the rack-jquery-params gem (disclaimer: I'm the author). It fixes your issue of arrays becoming hashes with integer keys.

참고URL : https://stackoverflow.com/questions/6410810/rails-not-decoding-json-from-jquery-correctly-array-becoming-a-hash-with-intege

반응형