如何验证此哈希参数?

时间:2015-01-01 04:44:58

标签: ruby grape grape-api

如何为此哈希参数编写正确的params验证:

{
  "files": {
    "main.c": {
      "contents": "#include <stdio.h> ...",
      "foo": "bar"
    },
    "main.h": {
      "contents": "#define BLAH ...",
      "foo": "baz"
    },
    ... more files here ...
  }
}

files是我要验证的哈希参数。 files的每个键都可以是任何键(字符串);值是具有特定格式的哈希值,也需要进行验证(需要contentsfoo)。我使用的是葡萄0.9.0。

这就是我想要的东西:

params do
  optional :files, type: Hash do
    requires <any key>, type: Hash do
      requires :contents, type: String
      requires :foo, type: String
    end
  end
end

我已阅读documentation,但我无法看到如何实现此类验证。它甚至可能吗?我是否需要编写自定义验证器?


另一种方法是改为:

{
  "files":
  [
    {
      "name":     "main.c",
      "contents": "#include <stdio.h> ...",
      "foo":      "bar"
    },
    {
      "name":     "main.h",
      "contents": "#define BLAH ...",
      "foo":      "baz"
    }
  ]
}

可以像这样轻松验证:

params do
  optional :files, type: Array do
    requires :name, type: String
    requires :contents, type: String
    requires :foo, type: String
  end
end

但现在我失去了拥有唯一文件名的能力。

1 个答案:

答案 0 :(得分:0)

基于grape documentation,我想出了编写自己的自定义验证器的想法,并选择第二种方法。

class UniqueHashAttributes < Grape::Validations::Base
  def validate_param!(attr_name, params)
    # assuming @option is an array
    @option.each do |attribute|
      # detects if the value of the attribute is found more than once
      if params[attr_name].group_by { |h| h[attribute] }.values.collect(&:size).max > 1
        fail Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)],
             message: "must have only unique values for properties: '#{@option.join(', ')}'"
      end
    end
  end
end

还可以报告显示唯一性违规的自定义错误。当然,这个原则也可以应用于执行不同于唯一性的验证。

如果您的应用程序中加载了此验证程序,您可以在params路径定义中使用它,如下所示:

params do
  optional :files, unique_hash_attributes: [:name], type: Array do
    requires :name, type: String
    requires :contents, type: String
    requires :foo, type: String
  end
end
post '/validation' do
  'passed'
end

通过此实现,您还可以通过将:foo字段(或任何其他字段)添加到唯一哈希属性的数组中来指定它是唯一的。

Hash值的任何验证(名称,内容,foo)在files验证器中保持不变,仍然适用。

包含以下数据的发布请求无法通过验证:

{   "files":
  [
    {
      "name":     "main.c",
      "contents": "#include <stdio.h> ...",
      "foo":      "bar"
    },
    {
      "name":     "main.c",
      "contents": "#define BLAH ...",
      "foo":      "baz"
    }
  ]
}