Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
* [#2710](https://github.com/ruby-grape/grape/pull/2710): Tidy up `Grape::DeclaredParamsHandler` - [@ericproulx](https://github.com/ericproulx).
* [#2714](https://github.com/ruby-grape/grape/pull/2714): Drop unused `Grape::Middleware::Globals` and its `grape.request*` env constants - [@ericproulx](https://github.com/ericproulx).
* [#2717](https://github.com/ruby-grape/grape/pull/2717): Convert `Grape::Exceptions::ErrorResponse` to a `Data` value object - [@ericproulx](https://github.com/ericproulx).
* [#2725](https://github.com/ruby-grape/grape/pull/2725): Encapsulate `Grape::Validations::Validators::Base` state behind readers; add `required?`/`allow_blank?` predicates - [@ericproulx](https://github.com/ericproulx).
* Your contribution here.

#### Fixes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ class AllOrNoneOfValidator < MultipleParamsBase
def validate_params!(params)
known_keys = all_keys
keys = keys_in_common(params, known_keys)
return if keys.empty? || keys.length == @attrs.length
return if keys.empty? || keys.length == attrs.length

validation_error!(known_keys)
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ class AtLeastOneOfValidator < MultipleParamsBase

def validate_params!(params)
known_keys = all_keys
return if hash_like?(params) && known_keys.intersect?(params.keys.map { |attr| @scope.full_name(attr) })
return if hash_like?(params) && known_keys.intersect?(params.keys.map { |attr| scope.full_name(attr) })

validation_error!(known_keys)
end
Expand Down
34 changes: 19 additions & 15 deletions lib/grape/validations/validators/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -69,32 +69,28 @@ def initialize(attrs, options, required, scope, opts)
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate(request)
return unless @scope.should_validate?(request.params)
return unless scope.should_validate?(request.params)

validate!(request.params)
end

def fail_fast?
@fail_fast
end

# Validates a given parameter hash.
# @note Override #validate_param! for per-parameter validation,
# or #validate if you need access to the entire request.
# @param params [Hash] parameters to validate
# @raise [Grape::Exceptions::Validation] if validation failed
# @return [void]
def validate!(params)
attributes = SingleAttributeIterator.new(@attrs, @scope, params)
attributes = SingleAttributeIterator.new(attrs, scope, params)
# we collect errors inside array because
# there may be more than one error per field
array_errors = nil

attributes.each do |val, attr_name, empty_val|
next if !@scope.required? && empty_val
next unless @scope.meets_dependency?(val, params)
next if !scope.required? && empty_val
next unless scope.meets_dependency?(val, params)

validate_param!(attr_name, val) if @required || (hash_like?(val) && val.key?(attr_name))
validate_param!(attr_name, val) if required? || (hash_like?(val) && val.key?(attr_name))
rescue Grape::Exceptions::Validation => e
(array_errors ||= []) << e
end
Expand All @@ -115,17 +111,25 @@ def validate_param!(attr_name, params)

private

def validation_error!(attr_name_or_params, message = @exception_message)
params = attr_name_or_params.is_a?(Array) ? attr_name_or_params : @scope.full_name(attr_name_or_params)
attr_reader :fail_fast, :options, :scope, :required, :allow_blank, :exception_message
alias required? required
alias allow_blank? allow_blank
alias fail_fast? fail_fast
# The only reader called across the validator boundary
# (Grape::Endpoint#run_validators); everything else is internal.
public :fail_fast?

def validation_error!(attr_name_or_params, message = exception_message)
params = attr_name_or_params.is_a?(Array) ? attr_name_or_params : scope.full_name(attr_name_or_params)
raise Grape::Exceptions::Validation.new(params:, message:)
end

def hash_like?(obj)
obj.respond_to?(:key?)
end

def options_key?(key, options = nil)
current_options = options || @options
def options_key?(key, given_options = nil)
current_options = given_options || options
hash_like?(current_options) && current_options.key?(key) && !current_options[key].nil?
end

Expand All @@ -137,14 +141,14 @@ def options_key?(key, options = nil)
# @exception_message = message(:presence) # symbol key or custom message
# @exception_message = message { build_hash_message } # computed fallback
def message(default_key = nil)
key = options_key?(:message) ? @options[:message] : default_key
key = options_key?(:message) ? options[:message] : default_key
return key unless key.nil?

yield if block_given?
end

def option_value
options_key?(:value) ? @options[:value] : @options
options_key?(:value) ? options[:value] : options
end

def scrub(value)
Expand Down
6 changes: 3 additions & 3 deletions lib/grape/validations/validators/coerce_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class CoerceValidator < Base
def initialize(attrs, options, required, scope, opts)
super

raw_type = @options[:type]
raw_type = options[:type]
type = hash_like?(raw_type) ? raw_type[:value] : raw_type
@converter =
if type.is_a?(Grape::Validations::Types::VariantCollectionCoercer)
type
else
Types.build_coercer(type, method: @options[:method])
Types.build_coercer(type, method: options[:method])
end
end

Expand All @@ -24,7 +24,7 @@ def validate_param!(attr_name, params)

new_value = coerce_value(params[attr_name])

validation_error!(attr_name, new_value.message || @exception_message) if new_value.is_a?(Types::InvalidValue)
validation_error!(attr_name, new_value.message || exception_message) if new_value.is_a?(Types::InvalidValue)

# Don't assign a value if it is identical. It fixes a problem with Hashie::Mash
# which looses wrappers for hashes and arrays after reassigning values
Expand Down
16 changes: 8 additions & 8 deletions lib/grape/validations/validators/default_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ def initialize(attrs, options, required, scope, opts)
super
# !important, lazy call at runtime
@default_call =
if @options.is_a?(Proc)
@options.arity.zero? ? proc { @options.call } : @options
elsif @options.duplicable?
proc { @options.dup }
if options.is_a?(Proc)
options.arity.zero? ? proc { options.call } : options
elsif options.duplicable?
proc { options.dup }
else
proc { @options }
proc { options }
end
end

def validate!(params)
attrs = SingleAttributeIterator.new(@attrs, @scope, params)
attrs.each do |resource_params, attr_name|
next unless @scope.meets_dependency?(resource_params, params)
attributes = SingleAttributeIterator.new(attrs, scope, params)
attributes.each do |resource_params, attr_name|
next unless scope.meets_dependency?(resource_params, params)

resource_params[attr_name] = @default_call.call(resource_params) if hash_like?(resource_params) && resource_params[attr_name].nil?
end
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/validators/length_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ class LengthValidator < Base
def initialize(attrs, options, required, scope, opts)
super

@min, @max, @is = @options.values_at(:min, :max, :is)
@min, @max, @is = options.values_at(:min, :max, :is)
validate_boundary!(:min, @min)
validate_boundary!(:max, @max)
raise ArgumentError, "min #{@min} cannot be greater than max #{@max}" if @min && @max && @min > @max
Expand Down
6 changes: 3 additions & 3 deletions lib/grape/validations/validators/multiple_params_base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ module Validations
module Validators
class MultipleParamsBase < Base
def validate!(params)
attributes = MultipleAttributesIterator.new(@attrs, @scope, params)
attributes = MultipleAttributesIterator.new(attrs, scope, params)
array_errors = []

attributes.each do |resource_params|
Expand All @@ -22,11 +22,11 @@ def validate!(params)
def keys_in_common(resource_params, known_keys = all_keys)
return [] unless hash_like?(resource_params)

known_keys & resource_params.keys.map! { |attr| @scope.full_name(attr) }
known_keys & resource_params.keys.map! { |attr| scope.full_name(attr) }
end

def all_keys
@attrs.map { |attr| @scope.full_name(attr) }
attrs.map { |attr| scope.full_name(attr) }
end
end
end
Expand Down
2 changes: 1 addition & 1 deletion lib/grape/validations/validators/oneof_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def initialize(attrs, options, required, scope, opts)

def validate_param!(attr_name, params)
value = params[attr_name]
return if value.nil? && !@required
return if value.nil? && !required?

winning_candidate = nil
@variants.each do |variant_validators|
Expand Down
10 changes: 5 additions & 5 deletions lib/grape/validations/validators/values_validator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ def validate_param!(attr_name, params)
val = scrub(params[attr_name])

return if val.nil? && !required_for_root_scope?
return if val != false && val.blank? && @allow_blank
return if val != false && val.blank? && allow_blank?
return if check_values?(val, attr_name)

validation_error!(attr_name)
Expand All @@ -55,12 +55,12 @@ def check_values?(val, attr_name)
end

def required_for_root_scope?
return false unless @required
return false unless required?

scope = @scope
scope = scope.parent while scope.lateral?
current_scope = scope
current_scope = current_scope.parent while current_scope.lateral?

scope.root?
current_scope.root?
end
end
end
Expand Down
Loading