Skip to content

Commit 3551c67

Browse files
committed
Modify declare for nested array and hash ruby-grape#2042
1 parent e0dfb9c commit 3551c67

File tree

3 files changed

+56
-19
lines changed

3 files changed

+56
-19
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
* [#2038](https://github.com/ruby-grape/grape/pull/2038): Travis - update ruby versions - [@ericproulx](https://github.com/ericproulx).
88

99
#### Fixes
10+
* [#2043](https://github.com/ruby-grape/grape/pull/2043): Modify declared for nested array and hash - [@kadotami](https://github.com/kadotami).
1011

1112
* Your contribution here.
1213

lib/grape/dsl/inside_route.rb

Lines changed: 37 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -28,36 +28,38 @@ def self.post_filter_methods(type)
2828
# Methods which should not be available in filters until the before filter
2929
# has completed
3030
module PostBeforeFilter
31-
def declared(passed_params, options = {}, declared_params = nil)
31+
def declared(passed_params, options = {}, declared_params = nil, params_nested_path = [])
3232
options = options.reverse_merge(include_missing: true, include_parent_namespaces: true)
3333
declared_params ||= optioned_declared_params(**options)
3434

3535
if passed_params.is_a?(Array)
36-
declared_array(passed_params, options, declared_params)
36+
declared_array(passed_params, options, declared_params, params_nested_path)
3737
else
38-
declared_hash(passed_params, options, declared_params)
38+
declared_hash(passed_params, options, declared_params, params_nested_path)
3939
end
4040
end
4141

4242
private
4343

44-
def declared_array(passed_params, options, declared_params)
44+
def declared_array(passed_params, options, declared_params, params_nested_path)
4545
passed_params.map do |passed_param|
46-
declared(passed_param || {}, options, declared_params)
46+
declared(passed_param || {}, options, declared_params, params_nested_path)
4747
end
4848
end
4949

50-
def declared_hash(passed_params, options, declared_params)
50+
def declared_hash(passed_params, options, declared_params, params_nested_path)
5151
declared_params.each_with_object(passed_params.class.new) do |declared_param, memo|
5252
if declared_param.is_a?(Hash)
5353
declared_param.each_pair do |declared_parent_param, declared_children_params|
54+
params_nested_path_dup = params_nested_path.dup
55+
params_nested_path_dup << declared_parent_param.to_s
5456
next unless options[:include_missing] || passed_params.key?(declared_parent_param)
5557

5658
passed_children_params = passed_params[declared_parent_param] || passed_params.class.new
5759
memo_key = optioned_param_key(declared_parent_param, options)
5860

59-
memo[memo_key] = handle_passed_param(declared_parent_param, passed_children_params) do
60-
declared(passed_children_params, options, declared_children_params)
61+
memo[memo_key] = handle_passed_param(passed_children_params, params_nested_path_dup) do
62+
declared(passed_children_params, options, declared_children_params, params_nested_path_dup)
6163
end
6264
end
6365
else
@@ -77,19 +79,34 @@ def declared_hash(passed_params, options, declared_params)
7779
end
7880
end
7981

80-
def handle_passed_param(declared_param, passed_children_params, &_block)
81-
should_be_empty_array?(declared_param, passed_children_params) ? [] : yield
82+
def handle_passed_param(passed_children_params, params_nested_path, &_block)
83+
if should_be_empty_hash?(passed_children_params, params_nested_path)
84+
{}
85+
elsif should_be_empty_array?(passed_children_params, params_nested_path)
86+
[]
87+
else
88+
yield
89+
end
8290
end
8391

84-
def should_be_empty_array?(declared_param, passed_children_params)
85-
declared_param_is_array?(declared_param) && passed_children_params.empty?
92+
def should_be_empty_array?(passed_children_params, params_nested_path)
93+
passed_children_params.empty? && declared_param_is_array?(params_nested_path)
8694
end
8795

88-
def declared_param_is_array?(declared_param)
89-
key = declared_param.to_s
96+
def declared_param_is_array?(params_nested_path)
97+
key = route_options_params_key(params_nested_path)
9098
route_options_params[key] && route_options_params[key][:type] == 'Array'
9199
end
92100

101+
def should_be_empty_hash?(passed_children_params, params_nested_path)
102+
passed_children_params.empty? && declared_param_is_hash?(params_nested_path)
103+
end
104+
105+
def declared_param_is_hash?(params_nested_path)
106+
key = route_options_params_key(params_nested_path)
107+
route_options_params[key] && route_options_params[key][:type] == 'Hash'
108+
end
109+
93110
def route_options_params
94111
options[:route_options][:params] || {}
95112
end
@@ -98,6 +115,12 @@ def optioned_param_key(declared_param, options)
98115
options[:stringify] ? declared_param.to_s : declared_param.to_sym
99116
end
100117

118+
def route_options_params_key(params_nested_path)
119+
key = params_nested_path[0]
120+
key += '[' + params_nested_path[1..-1].join('][') + ']' if params_nested_path.size > 1
121+
key
122+
end
123+
101124
def optioned_declared_params(**options)
102125
declared_params = if options[:include_parent_namespaces]
103126
# Declared params including parent namespaces

spec/grape/endpoint_spec.rb

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -296,9 +296,12 @@ def app
296296
optional :seventh
297297
end
298298
end
299+
optional :nested_arr, type: Array do
300+
optional :eighth
301+
end
299302
end
300-
optional :nested_arr, type: Array do
301-
optional :eighth
303+
optional :arr, type: Array do
304+
optional :nineth
302305
end
303306
end
304307
end
@@ -390,7 +393,7 @@ def app
390393

391394
get '/declared?first=present&nested[fourth]=1'
392395
expect(last_response.status).to eq(200)
393-
expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 3
396+
expect(JSON.parse(last_response.body)['nested'].keys.size).to eq 4
394397
end
395398

396399
it 'builds nested params when given array' do
@@ -421,7 +424,7 @@ def app
421424

422425
get '/declared?first=present'
423426
expect(last_response.status).to eq(200)
424-
expect(JSON.parse(last_response.body)['nested']).to be_a(Hash)
427+
expect(JSON.parse(last_response.body)['nested']).to eq({})
425428
end
426429

427430
it 'to be an array when include_missing is true' do
@@ -431,7 +434,17 @@ def app
431434

432435
get '/declared?first=present'
433436
expect(last_response.status).to eq(200)
434-
expect(JSON.parse(last_response.body)['nested_arr']).to be_a(Array)
437+
expect(JSON.parse(last_response.body)['arr']).to be_a(Array)
438+
end
439+
440+
it 'to be an array when nested and include_missing is true' do
441+
subject.get '/declared' do
442+
declared(params, include_missing: true)
443+
end
444+
445+
get '/declared?first=present&nested[fourth]=1'
446+
expect(last_response.status).to eq(200)
447+
expect(JSON.parse(last_response.body)['nested']['nested_arr']).to be_a(Array)
435448
end
436449

437450
it 'to be nil when include_missing is false' do

0 commit comments

Comments
 (0)