diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ac5d7c493..db52a5c905 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ Next Release ============ * Your contribution here. +* [#1503](/~https://github.com/ruby-grape/grape/pull/1503): Allow to use regexp validator with arrays - [@akoltun](/~https://github.com/akoltun). 0.18.0 (10/7/2016) ================== diff --git a/lib/grape/validations/validators/regexp.rb b/lib/grape/validations/validators/regexp.rb index 80fe4c12df..749a42ce2c 100644 --- a/lib/grape/validations/validators/regexp.rb +++ b/lib/grape/validations/validators/regexp.rb @@ -2,7 +2,8 @@ module Grape module Validations class RegexpValidator < Base def validate_param!(attr_name, params) - return unless params.key?(attr_name) && !params[attr_name].nil? && !(params[attr_name].to_s =~ (options_key?(:value) ? @option[:value] : @option)) + return unless params.respond_to?(:key?) && params.key?(attr_name) + return if Array.wrap(params[attr_name]).all? { |param| param.nil? || (param.to_s =~ (options_key?(:value) ? @option[:value] : @option)) } raise Grape::Exceptions::Validation, params: [@scope.full_name(attr_name)], message: message(:regexp) end end diff --git a/spec/grape/validations/validators/regexp_spec.rb b/spec/grape/validations/validators/regexp_spec.rb index 659bc61d29..cc2970a887 100644 --- a/spec/grape/validations/validators/regexp_spec.rb +++ b/spec/grape/validations/validators/regexp_spec.rb @@ -12,6 +12,12 @@ class API < Grape::API end get do end + + params do + requires :names, type: { value: Array[String], message: 'can\'t be nil' }, regexp: { value: /^[a-z]+$/, message: 'format is invalid' } + end + get 'regexp_with_array' do + end end params do @@ -19,6 +25,20 @@ class API < Grape::API end get do end + + params do + requires :names, type: Array[String], regexp: /^[a-z]+$/ + end + get 'regexp_with_array' do + end + + params do + requires :people, type: Hash do + requires :names, type: Array[String], regexp: /^[a-z]+$/ + end + end + get 'nested_regexp_with_array' do + end end end end @@ -51,6 +71,36 @@ def app get '/custom_message', name: 'bob' expect(last_response.status).to eq(200) end + + context 'regexp with array' do + it 'refuses inapppopriate items' do + get '/custom_message/regexp_with_array', names: ['invalid name', 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names format is invalid"}') + end + + it 'refuses empty items' do + get '/custom_message/regexp_with_array', names: ['', 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names format is invalid"}') + end + + it 'refuses nil items' do + get '/custom_message/regexp_with_array', names: [nil, 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names can\'t be nil"}') + end + + it 'accepts valid items' do + get '/custom_message/regexp_with_array', names: ['bob'] + expect(last_response.status).to eq(200) + end + + it 'accepts nil instead of array' do + get '/custom_message/regexp_with_array', names: nil + expect(last_response.status).to eq(200) + end + end end context 'invalid input' do @@ -76,4 +126,42 @@ def app get '/', name: 'bob' expect(last_response.status).to eq(200) end + + context 'regexp with array' do + it 'refuses inapppopriate items' do + get '/regexp_with_array', names: ['invalid name', 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names is invalid"}') + end + + it 'refuses empty items' do + get '/regexp_with_array', names: ['', 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names is invalid"}') + end + + it 'refuses nil items' do + get '/regexp_with_array', names: [nil, 'abc'] + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"names is invalid"}') + end + + it 'accepts valid items' do + get '/regexp_with_array', names: ['bob'] + expect(last_response.status).to eq(200) + end + + it 'accepts nil instead of array' do + get '/regexp_with_array', names: nil + expect(last_response.status).to eq(200) + end + end + + context 'nested regexp with array' do + it 'refuses inapppopriate' do + get '/nested_regexp_with_array', people: 'invalid name' + expect(last_response.status).to eq(400) + expect(last_response.body).to eq('{"error":"people is invalid, people[names] is missing, people[names] is invalid"}') + end + end end