Rails在请求的参数中将空数组转换为nils

Kar*_*lis 59 json ruby-on-rails

我的应用程序中有一个Backbone模型,它不是一个典型的扁平对象,它是一个大型嵌套对象,我们将嵌套部分存储在MySQL数据库的TEXT列中.

我想在Rails API中处理JSON编码/解码,以便从外部看起来你可以POST/GET这个大的嵌套JSON对象,即使它的一部分存储为字符串化的JSON文本.

但是,我遇到了一个问题,Rails神奇地将空数组转换为nil值.例如,如果我发布这个:

{
  name: "foo",
  surname: "bar",
  nested_json: {
    complicated: []
  }
}
Run Code Online (Sandbox Code Playgroud)

我的Rails控制器看到了这个:

{
  :name => "foo",
  :surname => "bar",
  :nested_json => {
    :complicated => nil
  }
}
Run Code Online (Sandbox Code Playgroud)

所以我的JSON数据已经改变了..

有没有人遇到过这个问题?为什么Rails会修改我的POST数据?

UPDATE

这是他们这样做的地方:

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

这是〜为什么他们这样做:

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

所以现在的问题是,如何在我的嵌套JSON API情况下最好地处理这个问题?

a10*_*10s 41

经过多次搜索,我发现你从Rails 4.1开始,你可以完全跳过deep_munge"功能"

config.action_dispatch.perform_deep_munge = false
Run Code Online (Sandbox Code Playgroud)

我找不到任何文档,但你可以在这里查看这个选项的介绍:https: //github.com/rails/rails/commit/e8572cf2f94872d81e7145da31d55c6e1b074247

这样做可能存在安全风险,请在此处记录:https://groups.google.com/forum/#!topic /rubyonrails- security/t1WFuuQyavI

  • 如果我使用较旧的rails版本,你知道如何禁用它吗? (2认同)

lat*_*lip 10

看起来这是一个已知的,最近推出的问题:https://github.com/rails/rails/issues/8832

如果您知道空数组的位置,您可以始终params[:...][:...] ||= []使用前过滤器.

或者,您可以将BackBone模型修改为JSON方法,JSON.stringify()在发布之前使用nested_json值显式字符串化,并使用JSON.parsebefore_filter 手动解析它.

丑陋,但它会起作用.


Gra*_*dpa 8

您可以自己重新解析参数,如下所示:

class ApiController
  before_filter :fix_json_params    # Rails 4 or earlier
  # before_action :fix_json_params  # Rails 5

  [...]

  protected

  def fix_json_params
    if request.content_type == "application/json"
      @reparsed_params = JSON.parse(request.body.string).with_indifferent_access
    end
  end

  private

  def params
    @reparsed_params || super
  end
end
Run Code Online (Sandbox Code Playgroud)

这通过查找具有JSON内容类型的请求,重新解析请求主体,然后拦截该params方法以返回重新解析的参数(如果它们存在)来工作.

  • 我发现[这个要点](https://gist.github.com/imanel/e01089009479a1596056)使用Rails 3.2.13. (3认同)
  • @Grandpa将重新解析的params与原始params合并不是更好吗?(例如,url请求参数将丢失) (3认同)