How to validate this hash parameter?

本秂侑毒 提交于 2019-12-21 05:16:20

问题


How do I write the correct params validations for this hash parameter:

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

files is the hash parameter that I want to validate. Each key of files can be anything (a string); the values are hashes with a specific format that also needs to be validated (requires contents and foo). I'm using grape 0.9.0.

This is kind of what I want to have:

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

I've read the documentation but I couldn't see how to achieve this kind of validation. Is it even possible? Do I need to write a custom validator?


An alternative is to have this instead:

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

which can be easily validated like this:

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

but now I lose the ability to have unique file names.


回答1:


Based on the grape documentation I would come up with the idea of writing your own custom validator and go with your second alternative.

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

It would also be possible to report custom errors that present the uniqueness violations. Of course this principle can also be applied to perform different kind of validations than the uniqueness.

If this validator is loaded in your application, you can utilize it in your params definition of the route as follows:

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

With this implementation you could also specify the :foo field (or any other) to be unique by adding it to the array of the unique hash attributes.

Any validations of the Hash's values (name, contents, foo) remain unchanged of the files validator and still apply.

A post request with the following data would not pass the verification:

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


来源:https://stackoverflow.com/questions/27728326/how-to-validate-this-hash-parameter

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!