Skip to content

Commit 9f44aa2

Browse files
authored
Ensure inherited nested exposures are merged (#72)
* Ensure inherited hash exposure are merged * Add changelog entry for #72 * Add missing period at the end of the line
1 parent 2ea7799 commit 9f44aa2

File tree

3 files changed

+103
-10
lines changed

3 files changed

+103
-10
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
#### Fixes
88

99
* Your contribution here.
10+
* [#72](https://github.com/ruby-grape/grape-swagger-entity/pull/72): Ensure inherited nested exposures are merged - [@pirhoo](https://github.com/pirhoo).
1011
* [#71](https://github.com/ruby-grape/grape-swagger-entity/pull/71): Fix regression for enum values in array attributes - [@Jell](https://github.com/Jell).
1112

1213
### 0.5.4 (2024/04/19)

lib/grape-swagger/entity/parser.rb

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -101,19 +101,22 @@ def add_discriminator(parsed, discriminator)
101101
end
102102

103103
def parse_nested(entity_name, entity_options, parent_model = nil)
104-
nested_entity = if parent_model.nil?
105-
model.root_exposures.find_by(entity_name)
106-
else
107-
parent_model.nested_exposures.find_by(entity_name)
108-
end
109-
110-
params = nested_entity.nested_exposures.each_with_object({}) do |value, memo|
104+
nested_entities = if parent_model.nil?
105+
model.root_exposures.select_by(entity_name)
106+
else
107+
parent_model.nested_exposures.select_by(entity_name)
108+
end
109+
110+
params = nested_entities
111+
.map(&:nested_exposures)
112+
.flatten
113+
.each_with_object({}) do |value, memo|
111114
memo[value.attribute] = value.send(:options)
112115
end
113116

114-
properties, required = parse_grape_entity_params(params, nested_entity)
115-
is_a_collection = entity_options[:documentation].is_a?(Hash) &&
116-
entity_options[:documentation][:type].to_s.casecmp('array').zero?
117+
properties, required = parse_grape_entity_params(params, nested_entities.last)
118+
documentation = entity_options[:documentation]
119+
is_a_collection = documentation.is_a?(Hash) && documentation[:type].to_s.casecmp('array').zero?
117120

118121
if is_a_collection
119122
{

spec/grape-swagger/entities/response_model_spec.rb

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,28 @@ class Nested < Grape::Entity
137137
end
138138
end
139139

140+
class NestedChild < Nested
141+
expose :nested, documentation: { type: Hash, desc: 'Nested entity' } do
142+
expose :some3, documentation: { type: 'String', desc: 'Nested some 3' }
143+
end
144+
145+
expose :nested_with_alias, as: :aliased do
146+
expose :some2, documentation: { type: 'String', desc: 'Alias some 2' }
147+
end
148+
149+
expose :deep_nested, documentation: { type: 'Object', desc: 'Deep nested entity' } do
150+
expose :level_1, documentation: { type: 'Object', desc: 'More deepest nested entity' } do
151+
expose :level_2, documentation: { type: 'String', desc: 'Level 2' } do
152+
expose :level_3, documentation: { type: 'String', desc: 'Level 3' }
153+
end
154+
end
155+
end
156+
157+
expose :nested_array, documentation: { type: 'Array', desc: 'Nested array' } do
158+
expose :category, documentation: { type: 'String', desc: 'Collection element category' }
159+
end
160+
end
161+
140162
class Polymorphic < Grape::Entity
141163
expose :obj, as: :kind, if: lambda { |instance, _|
142164
instance.type == 'kind'
@@ -162,6 +184,7 @@ class SomeEntity < Grape::Entity
162184
documentation: { type: 'TheseApi_Relation', desc: 'A related model.' }
163185
expose :values, using: TheseApi::Entities::Values, documentation: { desc: 'Tertiary kind.' }
164186
expose :nested, using: TheseApi::Entities::Nested, documentation: { desc: 'Nested object.' }
187+
expose :nested_child, using: TheseApi::Entities::NestedChild, documentation: { desc: 'Nested child object.' }
165188
expose :polymorphic, using: TheseApi::Entities::Polymorphic, documentation: { desc: 'Polymorphic Model' }
166189
expose :merged_attribute, using: ThisApi::Entities::Nested, merge: true
167190
end
@@ -268,6 +291,70 @@ def app
268291
},
269292
'type' => 'object'
270293
)
294+
expect(subject['TheseApi_Entities_NestedChild']).to eq(
295+
'properties' => {
296+
'nested' => {
297+
'type' => 'object',
298+
'properties' => {
299+
'some1' => { 'type' => 'string', 'description' => 'Nested some 1' },
300+
'some2' => { 'type' => 'string', 'description' => 'Nested some 2' },
301+
'some3' => { 'type' => 'string', 'description' => 'Nested some 3' }
302+
},
303+
'description' => 'Nested entity'
304+
},
305+
'aliased' => {
306+
'type' => 'object',
307+
'properties' => {
308+
'some1' => { 'type' => 'string', 'description' => 'Alias some 1' },
309+
'some2' => { 'type' => 'string', 'description' => 'Alias some 2' }
310+
}
311+
},
312+
'deep_nested' => {
313+
'type' => 'object',
314+
'properties' => {
315+
'level_1' => {
316+
'type' => 'object',
317+
'properties' => {
318+
'level_2' => {
319+
'type' => 'object',
320+
'properties' => {
321+
'level_3' => {
322+
'type' => 'string',
323+
'description' => 'Level 3'
324+
}
325+
},
326+
'description' => 'Level 2'
327+
}
328+
},
329+
'description' => 'More deepest nested entity'
330+
}
331+
},
332+
'description' => 'Deep nested entity'
333+
},
334+
'nested_required' => {
335+
'type' => 'object',
336+
'properties' => {
337+
'some1' => { 'type' => 'string', 'description' => 'Required some 1' },
338+
'some2' => { 'type' => 'string', 'description' => 'Required some 2' },
339+
'some3' => { 'type' => 'string', 'description' => 'Optional some 3' }
340+
},
341+
'required' => %w[some1 some2]
342+
},
343+
'nested_array' => {
344+
'type' => 'array',
345+
'items' => {
346+
'type' => 'object',
347+
'properties' => {
348+
'id' => { 'type' => 'integer', 'format' => 'int32', 'description' => 'Collection element id' },
349+
'name' => { 'type' => 'string', 'description' => 'Collection element name' },
350+
'category' => { 'type' => 'string', 'description' => 'Collection element category' }
351+
}
352+
},
353+
'description' => 'Nested array'
354+
}
355+
},
356+
'type' => 'object'
357+
)
271358
expect(subject['TheseApi_Entities_Polymorphic']).to eql(
272359
'type' => 'object',
273360
'properties' => {
@@ -290,6 +377,8 @@ def app
290377
'relation' => { '$ref' => '#/definitions/TheseApi_Entities_Relation', 'description' => 'A related model.' },
291378
'values' => { '$ref' => '#/definitions/TheseApi_Entities_Values', 'description' => 'Tertiary kind.' },
292379
'nested' => { '$ref' => '#/definitions/TheseApi_Entities_Nested', 'description' => 'Nested object.' },
380+
'nested_child' => { '$ref' => '#/definitions/TheseApi_Entities_NestedChild',
381+
'description' => 'Nested child object.' },
293382
'code' => { 'type' => 'string', 'description' => 'Error code' },
294383
'message' => { 'type' => 'string', 'description' => 'Error message' },
295384
'polymorphic' => { '$ref' => '#/definitions/TheseApi_Entities_Polymorphic',

0 commit comments

Comments
 (0)