Skip to content

Commit f0781fc

Browse files
author
Tim Connor
committed
Ensure complete declared params structure is present
1 parent 1201710 commit f0781fc

File tree

2 files changed

+51
-33
lines changed

2 files changed

+51
-33
lines changed

lib/grape/dsl/inside_route.rb

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,10 +70,14 @@ def declared_hash(passed_params, options, declared_params, params_nested_path)
7070

7171
next unless options[:include_missing] || passed_params.key?(declared_param) || (param_renaming && passed_params.key?(param_renaming))
7272

73-
if param_renaming
74-
memo[optioned_param_key(param_renaming, options)] = passed_params[param_renaming]
75-
else
76-
memo[optioned_param_key(declared_param, options)] = passed_params[declared_param]
73+
memo_key = optioned_param_key(param_renaming || declared_param, options)
74+
passed_param = passed_params[param_renaming || declared_param]
75+
76+
params_nested_path_dup = params_nested_path.dup
77+
params_nested_path_dup << declared_param.to_s
78+
79+
memo[memo_key] = handle_passed_param([], params_nested_path_dup) do
80+
passed_param
7781
end
7882
end
7983
end
@@ -99,12 +103,14 @@ def declared_param_is_array?(params_nested_path)
99103
end
100104

101105
def should_be_empty_hash?(passed_children_params, params_nested_path)
102-
passed_children_params.empty? && declared_param_is_hash?(params_nested_path)
106+
passed_children_params.empty? && declared_param_is_empty_hash?(params_nested_path)
103107
end
104108

105-
def declared_param_is_hash?(params_nested_path)
109+
def declared_param_is_empty_hash?(params_nested_path)
106110
key = route_options_params_key(params_nested_path)
107-
route_options_params[key] && route_options_params[key][:type] == 'Hash'
111+
has_children = route_options_params.keys.any? { |k| k != key && k.start_with?(key) }
112+
113+
route_options_params[key] && route_options_params[key][:type] == 'Hash' && !has_children
108114
end
109115

110116
def route_options_params

spec/grape/endpoint/declared_spec.rb

Lines changed: 38 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,14 @@ def app
2828
optional :nested_arr, type: Array do
2929
optional :eighth
3030
end
31+
optional :empty_arr, type: Array
32+
optional :empty_hash, type: Hash
3133
end
3234
optional :arr, type: Array do
3335
optional :nineth
3436
end
37+
optional :empty_arr, type: Array
38+
optional :empty_hash, type: Hash
3539
end
3640
end
3741

@@ -103,7 +107,7 @@ def app
103107
end
104108
get '/declared?first=present'
105109
expect(last_response.status).to eq(200)
106-
expect(JSON.parse(last_response.body).keys.size).to eq(5)
110+
expect(JSON.parse(last_response.body).keys.size).to eq(7)
107111
end
108112

109113
it 'has a optional param with default value all the time' do
@@ -122,7 +126,7 @@ def app
122126

123127
get '/declared?first=present&nested[fourth]=1'
124128
expect(last_response.status).to eq(200)
125-
expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 4
129+
expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 6
126130
end
127131

128132
it 'builds nested params when given array' do
@@ -145,45 +149,53 @@ def app
145149
expect(JSON.parse(last_response.body)['nested'].size).to eq 2
146150
end
147151

148-
context 'sets nested objects when the param is missing' do
149-
it 'to be a hash when include_missing is true' do
150-
subject.get '/declared' do
151-
declared(params, include_missing: true)
152-
end
152+
context 'when the param is missing and include_missing=false' do
153+
before do
154+
subject.get('/declared') { declared(params, include_missing: false) }
155+
end
153156

157+
it 'sets nested objects to be nil' do
154158
get '/declared?first=present'
155159
expect(last_response.status).to eq(200)
156-
expect(JSON.parse(last_response.body)['nested']).to eq({})
160+
expect(JSON.parse(last_response.body)['nested']).to be_nil
157161
end
162+
end
158163

159-
it 'to be an array when include_missing is true' do
160-
subject.get '/declared' do
161-
declared(params, include_missing: true)
162-
end
164+
context 'when the param is missing and include_missing=true' do
165+
before do
166+
subject.get('/declared') { declared(params, include_missing: true) }
167+
end
163168

169+
it 'sets objects with type=Hash to be a hash' do
164170
get '/declared?first=present'
165171
expect(last_response.status).to eq(200)
166-
expect(JSON.parse(last_response.body)['arr']).to be_a(Array)
167-
end
168172

169-
it 'to be an array when nested and include_missing is true' do
170-
subject.get '/declared' do
171-
declared(params, include_missing: true)
172-
end
173+
body = JSON.parse(last_response.body)
174+
expect(body['empty_hash']).to eq({})
175+
expect(body['nested']).to be_a(Hash)
176+
expect(body['nested']['empty_hash']).to eq({})
177+
expect(body['nested']['nested_two']).to be_a(Hash)
178+
end
173179

174-
get '/declared?first=present&nested[fourth]=1'
180+
it 'sets objects with type=Array to be an array' do
181+
get '/declared?first=present'
175182
expect(last_response.status).to eq(200)
176-
expect(JSON.parse(last_response.body)['nested']['nested_arr']).to be_a(Array)
177-
end
178183

179-
it 'to be nil when include_missing is false' do
180-
subject.get '/declared' do
181-
declared(params, include_missing: false)
182-
end
184+
body = JSON.parse(last_response.body)
185+
expect(body['empty_arr']).to eq([])
186+
expect(body['arr']).to eq([])
187+
expect(body['nested']['empty_arr']).to eq([])
188+
expect(body['nested']['nested_arr']).to eq([])
189+
end
183190

191+
it 'includes all declared children when type=Hash' do
184192
get '/declared?first=present'
185193
expect(last_response.status).to eq(200)
186-
expect(JSON.parse(last_response.body)['nested']).to be_nil
194+
195+
body = JSON.parse(last_response.body)
196+
expect(body['nested'].keys).to eq(%w[fourth fifth nested_two nested_arr empty_arr empty_hash])
197+
expect(body['nested']['nested_two'].keys).to eq(%w[sixth nested_three])
198+
expect(body['nested']['nested_two']['nested_three'].keys).to eq(%w[seventh])
187199
end
188200
end
189201

0 commit comments

Comments
 (0)