From d1dfdccca242e00d4d88064a013f92e89a76dbd2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Pedro=20Marques?= <64037198+TheDevJoao@users.noreply.github.com> Date: Mon, 5 Jun 2023 14:50:44 -0300 Subject: [PATCH] Feature: Allows procs with arity 1 to validate and use custom messages (#2333) * refactor: validate_param! method - now allows a proc to validate and use custom messages - adds @proc_message instance variable - creates the skip_validation? method to pass rubocops cyclomatic error * Adds changelog entry * Adds PR # to the changelog * Properly formats the changelog line * Places the changelog line in the correct order * Adds default changelog message for future use * Edits the changelog with a better description * refactor: allows procs with an arity of 1 * Adds a test for when arity is > 1 --- CHANGELOG.md | 1 + .../validators/values_validator.rb | 13 ++++++- .../validations/validators/values_spec.rb | 37 +++++++++++++++++++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 344022f763..eaf3316295 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,7 @@ * [#2330](https://github.com/ruby-grape/grape/pull/2330): Use ActiveSupport inflector - [@ericproulx](https://github.com/ericproulx). * [#2331](https://github.com/ruby-grape/grape/pull/2331): Memory optimization when running validators - [@ericproulx](https://github.com/ericproulx). * [#2332](https://github.com/ruby-grape/grape/pull/2332): Use ActiveSupport configurable - [@ericproulx](https://github.com/ericproulx). +* [#2333](https://github.com/ruby-grape/grape/pull/2333): Use custom messages in parameter validation with arity 1 - [@thedevjoao](https://github.com/TheDevJoao). * Your contribution here. #### Fixes diff --git a/lib/grape/validations/validators/values_validator.rb b/lib/grape/validations/validators/values_validator.rb index 0fba1a91c3..2b7aca76ed 100644 --- a/lib/grape/validations/validators/values_validator.rb +++ b/lib/grape/validations/validators/values_validator.rb @@ -43,7 +43,7 @@ def validate_param!(attr_name, params) unless check_values(param_array, attr_name) raise validation_exception(attr_name, message(:values)) \ - if @proc && !param_array.all? { |param| @proc.call(param) } + if @proc && !validate_proc(@proc, param_array) end private @@ -68,6 +68,17 @@ def check_excepts(param_array) param_array.none? { |param| excepts.include?(param) } end + def validate_proc(proc, param_array) + case proc.arity + when 0 + param_array.all? { |_param| proc.call } + when 1 + param_array.all? { |param| proc.call(param) } + else + raise ArgumentError, 'proc arity must be 0 or 1' + end + end + def except_message options = instance_variable_get(:@option) options_key?(:except_message) ? options[:except_message] : message(:except_values) diff --git a/spec/grape/validations/validators/values_spec.rb b/spec/grape/validations/validators/values_spec.rb index 43b8ea698f..d8ef17c95b 100644 --- a/spec/grape/validations/validators/values_spec.rb +++ b/spec/grape/validations/validators/values_spec.rb @@ -30,6 +30,10 @@ def add_except(except) def include?(value) values.include?(value) end + + def even?(value) + value.to_i.even? + end end end end @@ -241,6 +245,18 @@ def include?(value) end get '/proc/message' + params do + requires :number, values: { value: ->(v) { ValuesModel.even? v }, message: 'must be even' } + end + get '/proc/custom_message' do + { message: 'success' } + end + + params do + requires :input_one, :input_two, values: { value: ->(v1, v2) { v1 + v2 > 10 } } + end + get '/proc/arity2' + params do optional :name, type: String, values: %w[a b], allow_blank: true end @@ -692,5 +708,26 @@ def app expect(last_response.status).to eq 400 expect(last_response.body).to eq({ error: 'type failed check' }.to_json) end + + context 'when proc has an arity of 1' do + it 'accepts a valid value' do + get '/proc/custom_message', number: 4 + expect(last_response.status).to eq 200 + expect(last_response.body).to eq({ message: 'success' }.to_json) + end + + it 'rejects an invalid value' do + get '/proc/custom_message', number: 5 + expect(last_response.status).to eq 400 + expect(last_response.body).to eq({ error: 'number must be even' }.to_json) + end + end + + context 'when arity is > 1' do + it 'returns an error status code' do + get '/proc/arity2', input_one: 2, input_two: 3 + expect(last_response.status).to eq 400 + end + end end end