Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Rails converts empty arrays into nils in params of the request

I have a Backbone model in my app which is not a typical flat object, it's a large nested object and we store the nested parts in TEXT columns in a MySQL database.

I wanted to handle the JSON encoding/decoding in Rails API so that from outside it looks like you can POST/GET this one large nested JSON object even if parts of it are stored as stringified JSON text.

However, I ran into an issue where Rails magically converts empty arrays to nil values. For example, if I POST this:

{   name: "foo",   surname: "bar",   nested_json: {     complicated: []   } } 

My Rails controller sees this:

{   :name => "foo",   :surname => "bar",   :nested_json => {     :complicated => nil   } } 

And so my JSON data has been altered..

Has anyone run into this issue before? Why would Rails be modifying my POST data?

UPDATE

Here is where they do it:

https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/http/request.rb#L288

And here is ~why they do it:

https://github.com/rails/rails/pull/8862

So now the question is, how to best deal with this in my nested JSON API situation?

like image 845
Karolis Avatar asked Feb 01 '13 13:02

Karolis


2 Answers

After much searching, I discovered that you starting in Rails 4.1 you can skip the deep_munge "feature" completely using

config.action_dispatch.perform_deep_munge = false 

I could not find any documentation, but you can view the introduction of this option here: https://github.com/rails/rails/commit/e8572cf2f94872d81e7145da31d55c6e1b074247

There is a possible security risk in doing so, documented here: https://groups.google.com/forum/#!topic/rubyonrails-security/t1WFuuQyavI

like image 183
a10s Avatar answered Sep 24 '22 14:09

a10s


Looks like this is a known, recently introduced issue: https://github.com/rails/rails/issues/8832

If you know where the empty array will be you could always params[:...][:...] ||= [] in a before filter.

Alternatively you could modify your BackBone model's to JSON method, explicitly stringifying the nested_json value using JSON.stringify() before it gets posted and manually parsing it back out using JSON.parse in a before_filter.

Ugly, but it'll work.

like image 31
latentflip Avatar answered Sep 22 '22 14:09

latentflip