diff --git a/CHANGELOG.md b/CHANGELOG.md index fd35541b..54d89f15 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ #### Fixes +* [#986](https://github.com/ruby-grape/grape-swagger/pull/986): Read a route's tags through `route.tags` instead of `route.options`; a blank `tags:` (`nil` or `[]`) now means "not specified" and derives the tag from the path. See [UPGRADING](UPGRADING.md) - [@ericproulx](https://github.com/ericproulx). * Your contribution here. ### 2.2.0 (2026-08-06) diff --git a/README.md b/README.md index 1766ffff..a6a85275 100644 --- a/README.md +++ b/README.md @@ -648,6 +648,8 @@ end Tags are used for logical grouping of operations by resources or any other qualifier. To override the tags array, add `tags: ['tag1', 'tag2']` after the description. +When `tags:` is not given, or is `nil` or empty, the tag is derived from the path. + ```ruby namespace 'order' do desc 'This will be your summary', tags: ['orders'] diff --git a/UPGRADING.md b/UPGRADING.md index 0fd5d24f..f8fb7dbd 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,5 +1,11 @@ ## Upgrading Grape-swagger +### Upgrading to >= 2.3.0 + +- **A blank `desc(..., tags:)` now means "not specified".** `tags: nil` no longer suppresses the tag and `tags: []` no longer emits an empty `"tags": []`; both derive the tag from the path, as if `tags:` had been omitted. `tags:` is an override, and only a non-empty list overrides anything. + + The old `nil` behaviour was never a deliberate one: [#523](https://github.com/ruby-grape/grape-swagger/pull/523) introduced route-level tags to *override* path-derived grouping and read them with `route.options.fetch(:tags, tag_object(route))`, whose default-on-absence semantics happened to give `nil` a meaning of its own. It was never documented or tested. + ### Upgrading to >= 2.2.0 - **Minimum Grape version is now `>= 2.1`** (was `>= 1.7`). Grape 1.8.0 and 2.0.0 cannot be used on Ruby 3.3+ because of an upstream Mustermann/forwardable incompatibility; the CI rows for those combinations were already failing on `master` and have been removed. diff --git a/lib/grape-swagger/endpoint.rb b/lib/grape-swagger/endpoint.rb index 70a8a8ea..fba5fb40 100644 --- a/lib/grape-swagger/endpoint.rb +++ b/lib/grape-swagger/endpoint.rb @@ -123,7 +123,7 @@ def method_object(route, options, path) method[:parameters] = params_object(route, options, path, method[:consumes]) method[:security] = security_object(route) method[:responses] = response_object(route, options) - method[:tags] = route.options.key?(:tags) ? route.tags : tag_object(route, path) + method[:tags] = route.tags.presence || tag_object(route, path) method[:operationId] = GrapeSwagger::DocMethods::OperationId.build(route, path) method[:deprecated] = deprecated_object(route) method.delete_if { |_, value| value.nil? } diff --git a/spec/swagger_v2/endpoint_versioned_path_spec.rb b/spec/swagger_v2/endpoint_versioned_path_spec.rb index d6cc2f1b..65766f08 100644 --- a/spec/swagger_v2/endpoint_versioned_path_spec.rb +++ b/spec/swagger_v2/endpoint_versioned_path_spec.rb @@ -65,8 +65,25 @@ end end - it 'omits the tags key instead of falling back to the default tag' do - expect(subject.first['/v1/item'][:get]).not_to have_key(:tags) + it 'falls back to the default tag' do + expect(subject.first['/v1/item'][:get][:tags]).to eq ['item'] + end + end + + context 'when tags are explicitly empty' do + let(:item) do + Class.new(Grape::API) do + version 'v1', using: :path + + resource :item do + desc 'Item description', tags: [] + get '/' + end + end + end + + it 'falls back to the default tag' do + expect(subject.first['/v1/item'][:get][:tags]).to eq ['item'] end end