class Grape::Validations::ParamsScope

Attributes

element[RW]
parent[RW]

Public Class Methods

new(opts, &block) click to toggle source
# File lib/grape/validations.rb, line 87
def initialize(opts, &block)
  @element  = opts[:element]
  @parent   = opts[:parent]
  @api      = opts[:api]
  @optional = opts[:optional] || false
  @type     = opts[:type]
  @declared_params = []

  instance_eval(&block)

  configure_declared_params
end

Public Instance Methods

exactly_one_of(*attrs) click to toggle source
# File lib/grape/validations.rb, line 137
def exactly_one_of(*attrs)
  validates(attrs, exactly_one_of: true)
end
full_name(name) click to toggle source
# File lib/grape/validations.rb, line 172
def full_name(name)
  return "#{@parent.full_name(@element)}[#{name}]" if @parent
  name.to_s
end
group(*attrs, &block) click to toggle source
# File lib/grape/validations.rb, line 141
def group(*attrs, &block)
  requires(*attrs, &block)
end
includes(*names)
Alias for: use
mutually_exclusive(*attrs) click to toggle source
# File lib/grape/validations.rb, line 133
def mutually_exclusive(*attrs)
  validates(attrs, mutual_exclusion: true)
end
optional(*attrs, &block) click to toggle source
# File lib/grape/validations.rb, line 121
def optional(*attrs, &block)
  orig_attrs = attrs

  validations = {}
  validations.merge!(attrs.pop) if attrs.last.is_a?(Hash)
  validations[:type] ||= Array if block_given?
  validates(attrs, validations)

  block_given? ? new_scope(orig_attrs, true, &block) :
    push_declared_params(attrs)
end
params(params) click to toggle source
# File lib/grape/validations.rb, line 145
def params(params)
  params = @parent.params(params) if @parent
  if @element
    if params.is_a?(Array)
      params = params.flat_map { |el| el[@element] || {} }
    elsif params.is_a?(Hash)
      params = params[@element] || {}
    else
      params = {}
    end
  end
  params
end
requires(*attrs, &block) click to toggle source
# File lib/grape/validations.rb, line 106
def requires(*attrs, &block)
  orig_attrs = attrs.clone

  opts = attrs.last.is_a?(Hash) ? attrs.pop : nil

  if opts && opts[:using]
    require_required_and_optional_fields(attrs.first, opts)
  else
    validate_attributes(attrs, opts, &block)

    block_given? ? new_scope(orig_attrs, &block) :
      push_declared_params(attrs)
  end
end
root?() click to toggle source
# File lib/grape/validations.rb, line 177
def root?
  !@parent
end
should_validate?(parameters) click to toggle source
# File lib/grape/validations.rb, line 100
def should_validate?(parameters)
  return false if @optional && params(parameters).respond_to?(:all?) && params(parameters).all?(&:blank?)
  return true if parent.nil?
  parent.should_validate?(parameters)
end
use(*names) click to toggle source
# File lib/grape/validations.rb, line 159
def use(*names)
  named_params = @api.settings[:named_params] || {}
  options = names.last.is_a?(Hash) ? names.pop : {}
  names.each do |name|
    params_block = named_params.fetch(name) do
      raise "Params :#{name} not found!"
    end
    instance_exec(options, &params_block)
  end
end
Also aliased as: use_scope, includes
use_scope(*names)
Alias for: use

Protected Instance Methods

push_declared_params(attrs) click to toggle source
# File lib/grape/validations.rb, line 183
def push_declared_params(attrs)
  @declared_params.concat attrs
end

Private Instance Methods

configure_declared_params() click to toggle source

Pushes declared params to parent or settings

# File lib/grape/validations.rb, line 222
def configure_declared_params
  if @parent
    @parent.push_declared_params [element => @declared_params]
  else
    @api.settings.peek[:declared_params] ||= []
    @api.settings[:declared_params].concat @declared_params
  end
end
new_scope(attrs, optional = false, &block) click to toggle source
# File lib/grape/validations.rb, line 215
def new_scope(attrs, optional = false, &block)
  opts = attrs[1] || { type: Array }
  raise ArgumentError unless opts.keys.to_set.subset? [:type].to_set
  ParamsScope.new(api: @api, element: attrs.first, parent: self, optional: optional, type: opts[:type], &block)
end
require_required_and_optional_fields(context, opts) click to toggle source
# File lib/grape/validations.rb, line 189
def require_required_and_optional_fields(context, opts)
  if context == :all
    optional_fields = Array(opts[:except])
    required_fields = opts[:using].keys - optional_fields
  else # context == :none
    required_fields = Array(opts[:except])
    optional_fields = opts[:using].keys - required_fields
  end
  required_fields.each do |field|
    field_opts = opts[:using][field]
    raise ArgumentError, "required field not exist: #{field}" unless field_opts
    requires(field, field_opts)
  end
  optional_fields.each do |field|
    field_opts = opts[:using][field]
    optional(field, field_opts) if field_opts
  end
end
validate(type, options, attrs, doc_attrs) click to toggle source
# File lib/grape/validations.rb, line 285
def validate(type, options, attrs, doc_attrs)
  validator_class = Validations.validators[type.to_s]

  if validator_class
    (@api.settings.peek[:validations] ||= []) << validator_class.new(attrs, options, doc_attrs[:required], self)
  else
    raise Grape::Exceptions::UnknownValidator.new(type)
  end
end
validate_attributes(attrs, opts, &block) click to toggle source
# File lib/grape/validations.rb, line 208
def validate_attributes(attrs, opts, &block)
  validations = { presence: true }
  validations.merge!(opts) if opts
  validations[:type] ||= Array if block
  validates(attrs, validations)
end
validates(attrs, validations) click to toggle source
# File lib/grape/validations.rb, line 231
def validates(attrs, validations)
  doc_attrs = { required: validations.keys.include?(:presence) }

  # special case (type = coerce)
  validations[:coerce] = validations.delete(:type) if validations.key?(:type)

  coerce_type = validations[:coerce]
  doc_attrs[:type] = coerce_type.to_s if coerce_type

  desc = validations.delete(:desc)
  doc_attrs[:desc] = desc if desc

  default = validations[:default]
  doc_attrs[:default] = default if default

  values = validations[:values]
  doc_attrs[:values] = values if values

  values = (values.is_a?(Proc) ? values.call : values)

  # default value should be present in values array, if both exist
  if default && values && !values.include?(default)
    raise Grape::Exceptions::IncompatibleOptionValues.new(:default, default, :values, values)
  end

  # type should be compatible with values array, if both exist
  if coerce_type && values && values.any? { |v| !v.kind_of?(coerce_type) }
    raise Grape::Exceptions::IncompatibleOptionValues.new(:type, coerce_type, :values, values)
  end

  doc_attrs[:documentation] = validations.delete(:documentation) if validations.key?(:documentation)

  full_attrs = attrs.collect { |name| { name: name, full_name: full_name(name) } }
  @api.document_attribute(full_attrs, doc_attrs)

  # Validate for presence before any other validators
  if validations.key?(:presence) && validations[:presence]
    validate('presence', validations[:presence], attrs, doc_attrs)
    validations.delete(:presence)
  end

  # Before we run the rest of the validators, lets handle
  # whatever coercion so that we are working with correctly
  # type casted values
  if validations.key? :coerce
    validate('coerce', validations[:coerce], attrs, doc_attrs)
    validations.delete(:coerce)
  end

  validations.each do |type, options|
    validate(type, options, attrs, doc_attrs)
  end
end