Created
May 14, 2014 17:22
-
-
Save jordaaash/260662acf75e66d9bf79 to your computer and use it in GitHub Desktop.
Grape: Use case for value coercion after or between running other validators
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ClampValidator < Grape::Validations::SingleOptionValidator | |
def validate_param!(attr_name, params) | |
params[attr_name] = clamp(params[attr_name], @option.min, @option.max) | |
end | |
def clamp (value, min, max) | |
[[value, max].min, min].max | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Companies < Grape::API | |
SEPARATOR_REGEXP = /,/ | |
INTEGER_REGEXP = /\A(0|[1-9][0-9]*)\z/ | |
ID_REGEXP = /\A([1-9][0-9]*)\z/ | |
IDS_REGEXP = /\A([1-9][0-9]*)(,([1-9][0-9]*))*\z/ | |
helpers do | |
params :filters do | |
# Example of coercing after RegExp validation for a non-zero Integer | |
optional :location, | |
regexp: ID_REGEXP, | |
convert: Integer | |
# Example of using coercion after RegExp validation and splitting a String into an Array | |
optional :services, | |
regexp: IDS_REGEXP, | |
split: SEPARATOR_REGEXP, | |
convert: Set[Integer] | |
end | |
params :pagination do | |
# Examples of using coercion after RegExp validation, but before clamping the value between a Range | |
optional :limit, | |
regexp: INTEGER_REGEXP, | |
convert: Integer, | |
clamp: [0..100], | |
default: 25 | |
optional :offset, | |
regexp: INTEGER_REGEXP, | |
convert: Integer, | |
clamp: [0..-1], | |
default: 0 | |
end | |
end | |
resource :companies do | |
params do | |
use :filters, :pagination | |
end | |
get do | |
location, services, offset, limit = params[:location], params[:services], params[:offset], params[:limit] | |
Company.where(location: location, services: services).offset(offset * limit).limit(limit).all | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Modified from https://github.com/intridea/grape/blob/master/lib/grape/validations/coerce.rb | |
# Set inclusion suggested at https://github.com/intridea/grape/pull/642 | |
class ConvertValidator < Grape::Validations::SingleOptionValidator | |
def validate_param!(attr_name, params) | |
unless params.is_a? Hash | |
raise Grape::Exceptions::Validation, | |
param: @scope.full_name(attr_name), message_key: :convert | |
end | |
new_value = convert_value(@option, params[attr_name]) | |
if valid_type?(new_value) | |
params[attr_name] = new_value | |
else | |
raise Grape::Exceptions::Validation, | |
param: @scope.full_name(attr_name), message_key: :convert | |
end | |
end | |
class InvalidValue | |
end | |
private | |
def _valid_array_type?(type, values) | |
values.all? do |val| | |
_valid_single_type?(type, val) | |
end | |
end | |
def _valid_single_type?(klass, val) | |
# allow nil, to ignore when a parameter is absent | |
return true if val.nil? | |
if klass == Virtus::Attribute::Boolean | |
val.is_a?(TrueClass) || val.is_a?(FalseClass) | |
elsif klass == Rack::Multipart::UploadedFile | |
val.is_a?(Hashie::Mash) && val.key?(:tempfile) | |
else | |
val.is_a?(klass) | |
end | |
end | |
def valid_type?(val) | |
if @option.is_a?(Array) || @option.is_a?(Set) | |
_valid_array_type?(@option.first, val) | |
else | |
_valid_single_type?(@option, val) | |
end | |
end | |
def convert_value(type, val) | |
# Don't coerce things other than nil to Arrays, Hashes, or Sets | |
return val || [] if type == Array | |
return val || Set.new if type == Set | |
return val || {} if type == Hash | |
converter = Virtus::Attribute.build(type) | |
converter.coerce(val) | |
# not the prettiest but some invalid coercion can currently trigger | |
# errors in Virtus (see coerce_spec.rb:75) | |
rescue | |
InvalidValue.new | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class SplitValidator < Grape::Validations::SingleOptionValidator | |
def validate_param!(attr_name, params) | |
params[attr_name] = params[attr_name].split(@option) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment