Skip to content

Commit f8aaaec

Browse files
authored
fix evaluate given in array (#2287)
* fix evaluate given in array * changelog * avoid a bug that may be caused by rack-test by modifying spec * changelog, spec * meets_dependency will use params directly instead of @parent.params(request_params) when request_params is not given * create attr_meets_dependency instand of changing meets_dependency to more complex
1 parent 0e727c1 commit f8aaaec

File tree

4 files changed

+202
-11
lines changed

4 files changed

+202
-11
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* [#2272](https://github.com/ruby-grape/grape/pull/2272): Added error on param init when provided type does not have `[]` coercion method, previously validation silently failed for any value - [@vasfed](https://github.com/Vasfed).
1313
* [#2274](https://github.com/ruby-grape/grape/pull/2274): Error middleware support using rack util's symbols as status - [@dhruvCW](https://github.com/dhruvCW).
1414
* [#2276](https://github.com/ruby-grape/grape/pull/2276): Fix exception super - [@ericproulx](https://github.com/ericproulx).
15-
* [#2285](https://github.com/ruby-grape/grape/pull/2285): Added :evaluate_given to declared(params) - [@zysend](https://github.com/zysend).
15+
* [#2285](https://github.com/ruby-grape/grape/pull/2285), [#2287](https://github.com/ruby-grape/grape/pull/2287): Added :evaluate_given to declared(params) - [@zysend](https://github.com/zysend).
1616
* Your contribution here.
1717

1818
#### Fixes

lib/grape/dsl/inside_route.rb

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ def self.post_filter_methods(type)
2828
# has completed
2929
module PostBeforeFilter
3030
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
31-
options = options.reverse_merge(include_missing: true, include_parent_namespaces: true, evaluate_given: false, request_params: passed_params)
31+
options = options.reverse_merge(include_missing: true, include_parent_namespaces: true, evaluate_given: false)
3232
declared_params ||= optioned_declared_params(**options)
3333

3434
if passed_params.is_a?(Array)
@@ -48,7 +48,7 @@ def declared_array(passed_params, options, declared_params, params_nested_path)
4848

4949
def declared_hash(passed_params, options, declared_params, params_nested_path)
5050
declared_params.each_with_object(passed_params.class.new) do |declared_param_attr, memo|
51-
next if options[:evaluate_given] && !declared_param_attr.meets_dependency?(options[:request_params])
51+
next if options[:evaluate_given] && !declared_param_attr.scope.attr_meets_dependency?(passed_params)
5252

5353
declared_hash_attr(passed_params, options, declared_param_attr.key, params_nested_path, memo)
5454
end

lib/grape/validations/params_scope.rb

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,6 @@ def initialize(key, scope)
2121
@scope = scope
2222
end
2323

24-
def meets_dependency?(request_params)
25-
return true if scope.nil?
26-
27-
scope.meets_dependency?(scope.params(request_params), request_params)
28-
end
29-
3024
# @return Array[Symbol, Hash[Symbol => Array]] declared_params with symbol instead of Attr
3125
def self.attrs_keys(declared_params)
3226
declared_params.map do |declared_param_attr|
@@ -101,6 +95,18 @@ def meets_dependency?(params, request_params)
10195

10296
return params.any? { |param| meets_dependency?(param, request_params) } if params.is_a?(Array)
10397

98+
meets_hash_dependency?(params)
99+
end
100+
101+
def attr_meets_dependency?(params)
102+
return true unless @dependent_on
103+
104+
return false if @parent.present? && !@parent.attr_meets_dependency?(params)
105+
106+
meets_hash_dependency?(params)
107+
end
108+
109+
def meets_hash_dependency?(params)
104110
# params might be anything what looks like a hash, so it must implement a `key?` method
105111
return false unless params.respond_to?(:key?)
106112

spec/grape/validations/params_scope_spec.rb

Lines changed: 187 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ def initialize(value)
690690
end
691691
end
692692

693-
context 'nested parameter' do
693+
context 'lateral hash parameter' do
694694
before do
695695
[true, false].each do |evaluate_given|
696696
subject.params do
@@ -729,7 +729,7 @@ def initialize(value)
729729
end
730730
end
731731

732-
context 'nested given parameter' do
732+
context 'lateral parameter within lateral hash parameter' do
733733
before do
734734
[true, false].each do |evaluate_given|
735735
subject.params do
@@ -789,6 +789,191 @@ def initialize(value)
789789
expect(JSON.parse(last_response.body)).to eq('a' => 'y', 'b' => { 'd' => 'd', 'f' => nil, 'e' => { 'i' => nil } })
790790
end
791791
end
792+
793+
context 'lateral parameter within an array param' do
794+
before do
795+
[true, false].each do |evaluate_given|
796+
subject.params do
797+
optional :array, type: Array do
798+
optional :a
799+
given :a do
800+
optional :b
801+
end
802+
end
803+
end
804+
subject.post("/evaluate_given_#{evaluate_given}") do
805+
declared(params, evaluate_given: evaluate_given).to_json
806+
end
807+
end
808+
end
809+
810+
it 'evaluate_given_false' do
811+
post '/evaluate_given_false', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
812+
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil, 'b' => 'b' }, { 'a' => 'a', 'b' => 'b' }])
813+
end
814+
815+
it 'evaluate_given_true' do
816+
post '/evaluate_given_true', { array: [{ b: 'b' }, { a: 'a', b: 'b' }] }.to_json, 'CONTENT_TYPE' => 'application/json'
817+
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => nil }, { 'a' => 'a', 'b' => 'b' }])
818+
end
819+
end
820+
821+
context 'nested given parameter' do
822+
before do
823+
[true, false].each do |evaluate_given|
824+
subject.params do
825+
optional :a
826+
optional :c
827+
given :a do
828+
given :c do
829+
optional :b
830+
end
831+
end
832+
end
833+
subject.post("/evaluate_given_#{evaluate_given}") do
834+
declared(params, evaluate_given: evaluate_given).to_json
835+
end
836+
end
837+
end
838+
839+
it 'evaluate_given_false' do
840+
post '/evaluate_given_false', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
841+
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => nil)
842+
843+
post '/evaluate_given_false', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
844+
expect(JSON.parse(last_response.body)).to eq('a' => nil, 'b' => 'b', 'c' => 'c')
845+
846+
post '/evaluate_given_false', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
847+
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
848+
end
849+
850+
it 'evaluate_given_true' do
851+
post '/evaluate_given_true', { a: 'a', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
852+
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'c' => nil)
853+
854+
post '/evaluate_given_true', { c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
855+
expect(JSON.parse(last_response.body)).to eq('a' => nil, 'c' => 'c')
856+
857+
post '/evaluate_given_true', { a: 'a', c: 'c', b: 'b' }.to_json, 'CONTENT_TYPE' => 'application/json'
858+
expect(JSON.parse(last_response.body)).to eq('a' => 'a', 'b' => 'b', 'c' => 'c')
859+
end
860+
end
861+
862+
context 'nested given parameter within an array param' do
863+
before do
864+
[true, false].each do |evaluate_given|
865+
subject.params do
866+
optional :array, type: Array do
867+
optional :a
868+
optional :c
869+
given :a do
870+
given :c do
871+
optional :b
872+
end
873+
end
874+
end
875+
end
876+
subject.post("/evaluate_given_#{evaluate_given}") do
877+
declared(params, evaluate_given: evaluate_given).to_json
878+
end
879+
end
880+
end
881+
882+
let :evaluate_given_params do
883+
{
884+
array: [
885+
{ a: 'a', b: 'b' },
886+
{ c: 'c', b: 'b' },
887+
{ a: 'a', c: 'c', b: 'b' }
888+
]
889+
}
890+
end
891+
892+
it 'evaluate_given_false' do
893+
post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
894+
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'b' => 'b', 'c' => nil }, { 'a' => nil, 'b' => 'b', 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
895+
end
896+
897+
it 'evaluate_given_true' do
898+
post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
899+
expect(JSON.parse(last_response.body)).to eq('array' => [{ 'a' => 'a', 'c' => nil }, { 'a' => nil, 'c' => 'c' }, { 'a' => 'a', 'b' => 'b', 'c' => 'c' }])
900+
end
901+
end
902+
903+
context 'nested given parameter within a nested given parameter within an array param' do
904+
before do
905+
[true, false].each do |evaluate_given|
906+
subject.params do
907+
optional :array, type: Array do
908+
optional :a
909+
optional :c
910+
given :a do
911+
given :c do
912+
optional :array, type: Array do
913+
optional :a
914+
optional :c
915+
given :a do
916+
given :c do
917+
optional :b
918+
end
919+
end
920+
end
921+
end
922+
end
923+
end
924+
end
925+
subject.post("/evaluate_given_#{evaluate_given}") do
926+
declared(params, evaluate_given: evaluate_given).to_json
927+
end
928+
end
929+
end
930+
931+
let :evaluate_given_params do
932+
{
933+
array: [{
934+
a: 'a',
935+
c: 'c',
936+
array: [
937+
{ a: 'a', b: 'b' },
938+
{ c: 'c', b: 'b' },
939+
{ a: 'a', c: 'c', b: 'b' }
940+
]
941+
}]
942+
}
943+
end
944+
945+
it 'evaluate_given_false' do
946+
expected_response_hash = {
947+
'array' => [{
948+
'a' => 'a',
949+
'c' => 'c',
950+
'array' => [
951+
{ 'a' => 'a', 'b' => 'b', 'c' => nil },
952+
{ 'a' => nil, 'c' => 'c', 'b' => 'b' },
953+
{ 'a' => 'a', 'c' => 'c', 'b' => 'b' }
954+
]
955+
}]
956+
}
957+
post '/evaluate_given_false', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
958+
expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
959+
end
960+
961+
it 'evaluate_given_true' do
962+
expected_response_hash = {
963+
'array' => [{
964+
'a' => 'a',
965+
'c' => 'c',
966+
'array' => [
967+
{ 'a' => 'a', 'c' => nil },
968+
{ 'a' => nil, 'c' => 'c' },
969+
{ 'a' => 'a', 'b' => 'b', 'c' => 'c' }
970+
]
971+
}]
972+
}
973+
post '/evaluate_given_true', evaluate_given_params.to_json, 'CONTENT_TYPE' => 'application/json'
974+
expect(JSON.parse(last_response.body)).to eq(expected_response_hash)
975+
end
976+
end
792977
end
793978
end
794979

0 commit comments

Comments
 (0)