4

我正在使用 Rails 5 创建 JSON Api。

我的控制器使用带有一个require属性的强参数,如下所示:

params.require(:require_attribute).permit(:permit_attribute1,:permit_attribute2)

通常我必须像这样发送我的 JSON:

{
    "require_attribute":{
        "permit_attribute1": "data",
        "permit_attribute2": "data"
    }
}

如果缺少必需的属性,我必须得到这个消息:

"ActionController::ParameterMissing: param is missing or the value is empty: require_attribute"

我的问题是,如果我从 JSON 中删除所需的属性并且我有一个permit与强参数共同的属性,它确实有效。

我发送的 JSON:

{
    "permit_attribute1": "data",
}

当我得到参数时,log我有:

{"permit1"=>data, "controller"=>"mycontroller", "action"=>"create", "require_attribute"=>{"permit1"=>1} }

似乎 Rails 创建了一个带有所需键的散列,而不是引发错误。但是我想在收到 JSON 时强制使用所需的属性。

有人有想法吗?

4

2 回答 2

4

强参数 API 的设计考虑了最常见的用例。它并不是解决所有白名单问题的灵丹妙药。

http://guides.rubyonrails.org/action_controller_overview.html#strong-parameters

require(key)

确保存在参数。如果存在,则返回给定键的参数,否则引发 ActionController::ParameterMissing错误。

http://api.rubyonrails.org/classes/ActionController/Parameters.html#method-i-require

从上面可以看出,在“平面”散列上设置所需参数并不是强参数 API 的真正用途。相反,它是围绕rails 约定构建的,其中params 嵌套在一个键下。

您可以使用“.require”一次拉出一个键,但这会相当笨拙。

相反,您可以通过引发异常来模拟它的作用,除非密钥存在:

def something_params
  req = [:required_attribute1, :required_attribute2]
  req.each do |k|
    raise ActionController::ParameterMissing.new(k) unless params[k].present?
  end
  whitelisted = params.permit(:permit_attribute1, :permit_attribute2)
end

然而,更好的方法可能是使用模型级别的验证——ActionController::ParameterMissing应该表明请求的一般格式是关闭的——而不是缺少必需的属性。例如,对于 JSONAPI.org 格式的请求,您将执行以下操作:

params.require(:data).require(:attributes).permit(:email, :username)

这确保了请求遵循标准。但是,强制在没有电子邮件的情况下无法创建用户是模型级别的问题。

于 2016-02-02T13:18:00.357 回答
2

是的,默认情况下,API 模式下的 Rails 将 JSON 请求参数包装到一个哈希中,从控制器类中猜测其名称。您可以在此处阅读详细信息。

如果您的应用中不需要此功能,只需:json从. 或者,您可以如上所述在控制器级别使用细粒度控制。:formatconfig\initializers\wrap_parameters.rb

这样,当所需的密钥不存在时,您将获得异常。

于 2019-07-18T07:42:05.980 回答