From a4824e5c8897a46dc6bc7163b099cbf2e5a085f7 Mon Sep 17 00:00:00 2001 From: Kenneth Bogner Date: Fri, 22 Aug 2025 12:28:20 -0400 Subject: [PATCH 1/2] Introduce UnprocessableContentStatus cop --- .../add_unprocessable_content_status_cop.md | 1 + config/default.yml | 8 ++ .../cop/rails/unprocessable_content_status.rb | 82 +++++++++++++++++++ lib/rubocop/cop/rails_cops.rb | 1 + .../unprocessable_content_status_spec.rb | 66 +++++++++++++++ 5 files changed, 158 insertions(+) create mode 100644 changelog/add_unprocessable_content_status_cop.md create mode 100644 lib/rubocop/cop/rails/unprocessable_content_status.rb create mode 100644 spec/rubocop/cop/rails/unprocessable_content_status_spec.rb diff --git a/changelog/add_unprocessable_content_status_cop.md b/changelog/add_unprocessable_content_status_cop.md new file mode 100644 index 0000000000..52e9243381 --- /dev/null +++ b/changelog/add_unprocessable_content_status_cop.md @@ -0,0 +1 @@ +* [#1520](https://github.com/rubocop/rubocop-rails/pull/1520): Add `Rails/UnprocessableContentStatus` cop ([@tuxagon][]) diff --git a/config/default.yml b/config/default.yml index 74bebd3142..ecad5febb1 100644 --- a/config/default.yml +++ b/config/default.yml @@ -1232,6 +1232,14 @@ Rails/UnknownEnv: - test - production +Rails/UnprocessableContentStatus: + Description: 'Use `:unprocessable_content` instead of `:unprocessable_entity`.' + Enabled: pending + Severity: warning + VersionAdded: '<>' + Include: + - '**/app/controllers/**/*.rb' + Rails/UnusedIgnoredColumns: Description: 'Remove a column that does not exist from `ignored_columns`.' Enabled: false diff --git a/lib/rubocop/cop/rails/unprocessable_content_status.rb b/lib/rubocop/cop/rails/unprocessable_content_status.rb new file mode 100644 index 0000000000..4e37e3dc4c --- /dev/null +++ b/lib/rubocop/cop/rails/unprocessable_content_status.rb @@ -0,0 +1,82 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Enforces the use of :unprocessable_content instead of :unprocessable_entity + # for HTTP status codes, as :unprocessable_entity is deprecated in Rack 3.1. + # + # @example + # # bad + # render json: { error: "Invalid data" }, status: :unprocessable_entity + # head :unprocessable_entity + # + # # good + # render json: { error: "Invalid data" }, status: :unprocessable_content + # head :unprocessable_content + # + class UnprocessableContentStatus < Base + extend AutoCorrector + + MSG = 'Use `:unprocessable_content` instead of `:unprocessable_entity`. ' \ + 'The `:unprocessable_entity` status is deprecated.' + + def_node_matcher :unprocessable_entity_symbol?, <<~PATTERN + (sym :unprocessable_entity) + PATTERN + + def_node_matcher :status_argument?, <<~PATTERN + (pair (sym :status) (sym :unprocessable_entity)) + PATTERN + + def on_sym(node) + return unless rack_3_1_or_newer? + + return unless unprocessable_entity_symbol?(node) + return if in_hash_key_context?(node) + + return unless status_related_context?(node) + + add_offense(node) do |corrector| + corrector.replace(node, ':unprocessable_content') + end + end + + def on_pair(node) + return unless rack_3_1_or_newer? + + status_argument?(node) do + add_offense(node.value) do |corrector| + corrector.replace(node.value, ':unprocessable_content') + end + end + end + + private + + def rack_3_1_or_newer? + Gem::Version.new(Rack::VERSION) >= Gem::Version.new('3.1.0') + rescue ArgumentError, NoMethodError + false + end + + def in_hash_key_context?(node) + node.parent&.pair_type? && node.parent.key == node + end + + def status_related_context?(node) + parent = node.parent + return false unless parent + + if parent.send_type? + method_name = parent.method_name + return %i[head render redirect_to].include?(method_name) + end + + # Variable assignment or ternary expression + %i[lvasgn if].include?(parent.type) + end + end + end + end +end diff --git a/lib/rubocop/cop/rails_cops.rb b/lib/rubocop/cop/rails_cops.rb index a8c7202dac..372e6551f5 100644 --- a/lib/rubocop/cop/rails_cops.rb +++ b/lib/rubocop/cop/rails_cops.rb @@ -136,6 +136,7 @@ require_relative 'rails/uniq_before_pluck' require_relative 'rails/unique_validation_without_index' require_relative 'rails/unknown_env' +require_relative 'rails/unprocessable_content_status' require_relative 'rails/unused_ignored_columns' require_relative 'rails/unused_render_content' require_relative 'rails/validation' diff --git a/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb b/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb new file mode 100644 index 0000000000..5c5f33a3f5 --- /dev/null +++ b/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Rails::UnprocessableContentStatus, :config do + context 'when Rack is older than 3.1 or not available' do + before do + allow(cop).to receive(:rack_3_1_or_newer?).and_return(false) + end + + it 'does nothing' do + expect_no_offenses(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_entity + RUBY + end + end + + context 'when Rack is 3.1 or later' do + before do + allow(cop).to receive(:rack_3_1_or_newer?).and_return(true) + end + + it 'registers an offense when using :unprocessable_entity in hash argument' do + expect_offense(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in head' do + expect_offense(<<~RUBY) + head :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + head :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in ternary expression' do + expect_offense(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_entity ? :unprocessable_content : :ok + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_content ? :unprocessable_content : :ok + RUBY + end + + it 'does not register an offense when using :unprocessable_content' do + expect_no_offenses(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_content + RUBY + end + + it 'does not register an offense when using :unprocessable_entity in hash key' do + expect_no_offenses(<<~RUBY) + { unprocessable_entity: 'Invalid data' } + RUBY + end + end +end From cbd47258e825b2ffad21300adfbf6fd89238c5af Mon Sep 17 00:00:00 2001 From: Kenneth Bogner Date: Fri, 22 Aug 2025 17:07:13 -0400 Subject: [PATCH 2/2] Rename cop and general for deprecated statuses --- .../add_unprocessable_content_status_cop.md | 1 - .../new_deprecated_http_status_names_cop.md | 1 + config/default.yml | 16 +- .../cop/rails/deprecated_http_status_names.rb | 81 ++++++++ .../cop/rails/unprocessable_content_status.rb | 82 -------- lib/rubocop/cop/rails_cops.rb | 2 +- .../deprecated_http_status_names_spec.rb | 194 ++++++++++++++++++ .../unprocessable_content_status_spec.rb | 66 ------ 8 files changed, 285 insertions(+), 158 deletions(-) delete mode 100644 changelog/add_unprocessable_content_status_cop.md create mode 100644 changelog/new_deprecated_http_status_names_cop.md create mode 100644 lib/rubocop/cop/rails/deprecated_http_status_names.rb delete mode 100644 lib/rubocop/cop/rails/unprocessable_content_status.rb create mode 100644 spec/rubocop/cop/rails/deprecated_http_status_names_spec.rb delete mode 100644 spec/rubocop/cop/rails/unprocessable_content_status_spec.rb diff --git a/changelog/add_unprocessable_content_status_cop.md b/changelog/add_unprocessable_content_status_cop.md deleted file mode 100644 index 52e9243381..0000000000 --- a/changelog/add_unprocessable_content_status_cop.md +++ /dev/null @@ -1 +0,0 @@ -* [#1520](https://github.com/rubocop/rubocop-rails/pull/1520): Add `Rails/UnprocessableContentStatus` cop ([@tuxagon][]) diff --git a/changelog/new_deprecated_http_status_names_cop.md b/changelog/new_deprecated_http_status_names_cop.md new file mode 100644 index 0000000000..d52b47a873 --- /dev/null +++ b/changelog/new_deprecated_http_status_names_cop.md @@ -0,0 +1 @@ +* [#1520](https://github.com/rubocop/rubocop-rails/pull/1520): New `Rails/DeprecatedHttpStatusNames` cop. ([@tuxagon][]) diff --git a/config/default.yml b/config/default.yml index ecad5febb1..82fb968010 100644 --- a/config/default.yml +++ b/config/default.yml @@ -394,6 +394,14 @@ Rails/DeprecatedActiveModelErrorsMethods: VersionAdded: '2.14' VersionChanged: '2.18' +Rails/DeprecatedHttpStatusNames: + Description: 'Use the new HTTP status names instead of deprecated ones.' + Enabled: pending + Severity: warning + VersionAdded: '<>' + Include: + - '**/app/controllers/**/*.rb' + Rails/DotSeparatedKeys: Description: 'Enforces the use of dot-separated keys instead of `:scope` options in `I18n` translation methods.' StyleGuide: 'https://rails.rubystyle.guide/#dot-separated-keys' @@ -1232,14 +1240,6 @@ Rails/UnknownEnv: - test - production -Rails/UnprocessableContentStatus: - Description: 'Use `:unprocessable_content` instead of `:unprocessable_entity`.' - Enabled: pending - Severity: warning - VersionAdded: '<>' - Include: - - '**/app/controllers/**/*.rb' - Rails/UnusedIgnoredColumns: Description: 'Remove a column that does not exist from `ignored_columns`.' Enabled: false diff --git a/lib/rubocop/cop/rails/deprecated_http_status_names.rb b/lib/rubocop/cop/rails/deprecated_http_status_names.rb new file mode 100644 index 0000000000..ac9796a4be --- /dev/null +++ b/lib/rubocop/cop/rails/deprecated_http_status_names.rb @@ -0,0 +1,81 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Rails + # Enforces the use of the current HTTP status names instead of deprecated ones. + # + # @example + # # bad + # render json: { error: "Invalid data" }, status: :unprocessable_entity + # head :payload_too_large + # + # # good + # render json: { error: "Invalid data" }, status: :unprocessable_content + # head :content_too_large + # + class DeprecatedHttpStatusNames < Base + extend AutoCorrector + + requires_gem 'rack', '>= 3.1.0' + + RESTRICT_ON_SEND = %i[render redirect_to head assert_response assert_redirected_to].freeze + + DEPRECATED_STATUSES = { + unprocessable_entity: :unprocessable_content, + payload_too_large: :content_too_large + }.freeze + + MSG = 'Use `:%s` instead of `:%s`. The `:%s` status is deprecated.' + + def_node_matcher :status_method_call, <<~PATTERN + { + (send nil? {:render :redirect_to} _ $hash) + (send nil? {:render :redirect_to} $hash) + (send nil? {:head :assert_response} $_ ...) + (send nil? :assert_redirected_to _ $hash ...) + (send nil? :assert_redirected_to $hash ...) + } + PATTERN + + def_node_matcher :status_hash_value, <<~PATTERN + (hash <(pair (sym :status) $_) ...>) + PATTERN + + def on_send(node) + status_method_call(node) do |status_node| + if status_node.hash_type? + # Handle hash arguments like { status: :unprocessable_entity } + status_hash_value(status_node) do |status_value| + find_deprecated_status_names(status_value) + end + else + # Handle positional arguments like head :unprocessable_entity + find_deprecated_status_names(status_node) + end + end + end + + private + + def find_deprecated_status_names(node) + if node.sym_type? && DEPRECATED_STATUSES.key?(node.value) + deprecated_status = node.value + preferred_status = DEPRECATED_STATUSES[deprecated_status] + + message = format(MSG, deprecated: deprecated_status, preferred: preferred_status) + + add_offense(node, message: message) do |corrector| + corrector.replace(node, ":#{preferred_status}") + end + elsif node.respond_to?(:children) + # Recursively search child nodes (handles ternary expressions, etc.) + node.children.each do |child| + find_deprecated_status_names(child) if child.is_a?(Parser::AST::Node) + end + end + end + end + end + end +end diff --git a/lib/rubocop/cop/rails/unprocessable_content_status.rb b/lib/rubocop/cop/rails/unprocessable_content_status.rb deleted file mode 100644 index 4e37e3dc4c..0000000000 --- a/lib/rubocop/cop/rails/unprocessable_content_status.rb +++ /dev/null @@ -1,82 +0,0 @@ -# frozen_string_literal: true - -module RuboCop - module Cop - module Rails - # Enforces the use of :unprocessable_content instead of :unprocessable_entity - # for HTTP status codes, as :unprocessable_entity is deprecated in Rack 3.1. - # - # @example - # # bad - # render json: { error: "Invalid data" }, status: :unprocessable_entity - # head :unprocessable_entity - # - # # good - # render json: { error: "Invalid data" }, status: :unprocessable_content - # head :unprocessable_content - # - class UnprocessableContentStatus < Base - extend AutoCorrector - - MSG = 'Use `:unprocessable_content` instead of `:unprocessable_entity`. ' \ - 'The `:unprocessable_entity` status is deprecated.' - - def_node_matcher :unprocessable_entity_symbol?, <<~PATTERN - (sym :unprocessable_entity) - PATTERN - - def_node_matcher :status_argument?, <<~PATTERN - (pair (sym :status) (sym :unprocessable_entity)) - PATTERN - - def on_sym(node) - return unless rack_3_1_or_newer? - - return unless unprocessable_entity_symbol?(node) - return if in_hash_key_context?(node) - - return unless status_related_context?(node) - - add_offense(node) do |corrector| - corrector.replace(node, ':unprocessable_content') - end - end - - def on_pair(node) - return unless rack_3_1_or_newer? - - status_argument?(node) do - add_offense(node.value) do |corrector| - corrector.replace(node.value, ':unprocessable_content') - end - end - end - - private - - def rack_3_1_or_newer? - Gem::Version.new(Rack::VERSION) >= Gem::Version.new('3.1.0') - rescue ArgumentError, NoMethodError - false - end - - def in_hash_key_context?(node) - node.parent&.pair_type? && node.parent.key == node - end - - def status_related_context?(node) - parent = node.parent - return false unless parent - - if parent.send_type? - method_name = parent.method_name - return %i[head render redirect_to].include?(method_name) - end - - # Variable assignment or ternary expression - %i[lvasgn if].include?(parent.type) - end - end - end - end -end diff --git a/lib/rubocop/cop/rails_cops.rb b/lib/rubocop/cop/rails_cops.rb index 372e6551f5..22b106b185 100644 --- a/lib/rubocop/cop/rails_cops.rb +++ b/lib/rubocop/cop/rails_cops.rb @@ -41,6 +41,7 @@ require_relative 'rails/delegate' require_relative 'rails/delegate_allow_blank' require_relative 'rails/deprecated_active_model_errors_methods' +require_relative 'rails/deprecated_http_status_names' require_relative 'rails/dot_separated_keys' require_relative 'rails/duplicate_association' require_relative 'rails/duplicate_scope' @@ -136,7 +137,6 @@ require_relative 'rails/uniq_before_pluck' require_relative 'rails/unique_validation_without_index' require_relative 'rails/unknown_env' -require_relative 'rails/unprocessable_content_status' require_relative 'rails/unused_ignored_columns' require_relative 'rails/unused_render_content' require_relative 'rails/validation' diff --git a/spec/rubocop/cop/rails/deprecated_http_status_names_spec.rb b/spec/rubocop/cop/rails/deprecated_http_status_names_spec.rb new file mode 100644 index 0000000000..c67d260437 --- /dev/null +++ b/spec/rubocop/cop/rails/deprecated_http_status_names_spec.rb @@ -0,0 +1,194 @@ +# frozen_string_literal: true + +RSpec.describe RuboCop::Cop::Rails::DeprecatedHttpStatusNames, :config do + context 'when Rack is older than 3.1' do + let(:gem_versions) { { 'rack' => '3.0.0' } } + + it 'does nothing' do + expect_no_offenses(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_entity + head :payload_too_large + RUBY + end + end + + context 'when Rack is 3.1 or later' do + let(:gem_versions) { { 'rack' => '3.1.0' } } + + context 'with :unprocessable_entity' do + it 'registers an offense when using :unprocessable_entity in render' do + expect_offense(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in head' do + expect_offense(<<~RUBY) + head :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + head :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in redirect_to' do + expect_offense(<<~RUBY) + redirect_to some_path, status: :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + redirect_to some_path, status: :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in assert_response' do + expect_offense(<<~RUBY) + assert_response :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + assert_response :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in assert_redirected_to' do + expect_offense(<<~RUBY) + assert_redirected_to some_path, status: :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + assert_redirected_to some_path, status: :unprocessable_content + RUBY + end + + it 'registers an offense when using :unprocessable_entity in ternary expression' do + expect_offense(<<~RUBY) + render json: { error: 'Invalid data' }, status: some_condition ? :unprocessable_entity : :ok + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'Invalid data' }, status: some_condition ? :unprocessable_content : :ok + RUBY + end + + it 'does not register an offense when using :unprocessable_content' do + expect_no_offenses(<<~RUBY) + render json: { error: 'Invalid data' }, status: :unprocessable_content + RUBY + end + + it 'does not register an offense when using :unprocessable_entity in hash key' do + expect_no_offenses(<<~RUBY) + { unprocessable_entity: 'Invalid data' } + RUBY + end + end + + context 'with :payload_too_large' do + it 'registers an offense when using :payload_too_large in render' do + expect_offense(<<~RUBY) + render json: { error: 'File too big' }, status: :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'File too big' }, status: :content_too_large + RUBY + end + + it 'registers an offense when using :payload_too_large in head' do + expect_offense(<<~RUBY) + head :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + head :content_too_large + RUBY + end + + it 'registers an offense when using :payload_too_large in redirect_to' do + expect_offense(<<~RUBY) + redirect_to some_path, status: :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + redirect_to some_path, status: :content_too_large + RUBY + end + + it 'registers an offense when using :payload_too_large in assert_response' do + expect_offense(<<~RUBY) + assert_response :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + assert_response :content_too_large + RUBY + end + + it 'registers an offense when using :payload_too_large in assert_redirected_to' do + expect_offense(<<~RUBY) + assert_redirected_to some_path, status: :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + assert_redirected_to some_path, status: :content_too_large + RUBY + end + + it 'registers an offense when using :payload_too_large in ternary expression' do + expect_offense(<<~RUBY) + render json: { error: 'File too big' }, status: some_condition ? :payload_too_large : :ok + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + render json: { error: 'File too big' }, status: some_condition ? :content_too_large : :ok + RUBY + end + + it 'does not register an offense when using :content_too_large' do + expect_no_offenses(<<~RUBY) + render json: { error: 'File too big' }, status: :content_too_large + RUBY + end + + it 'does not register an offense when using :payload_too_large in hash key' do + expect_no_offenses(<<~RUBY) + { payload_too_large: 'File too big' } + RUBY + end + end + + context 'with mixed deprecated statuses' do + it 'handles multiple deprecated statuses in the same code' do + expect_offense(<<~RUBY) + head :unprocessable_entity + ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. + head :payload_too_large + ^^^^^^^^^^^^^^^^^^ Use `:content_too_large` instead of `:payload_too_large`. The `:payload_too_large` status is deprecated. + RUBY + + expect_correction(<<~RUBY) + head :unprocessable_content + head :content_too_large + RUBY + end + end + end +end diff --git a/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb b/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb deleted file mode 100644 index 5c5f33a3f5..0000000000 --- a/spec/rubocop/cop/rails/unprocessable_content_status_spec.rb +++ /dev/null @@ -1,66 +0,0 @@ -# frozen_string_literal: true - -RSpec.describe RuboCop::Cop::Rails::UnprocessableContentStatus, :config do - context 'when Rack is older than 3.1 or not available' do - before do - allow(cop).to receive(:rack_3_1_or_newer?).and_return(false) - end - - it 'does nothing' do - expect_no_offenses(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_entity - RUBY - end - end - - context 'when Rack is 3.1 or later' do - before do - allow(cop).to receive(:rack_3_1_or_newer?).and_return(true) - end - - it 'registers an offense when using :unprocessable_entity in hash argument' do - expect_offense(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_entity - ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. - RUBY - - expect_correction(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_content - RUBY - end - - it 'registers an offense when using :unprocessable_entity in head' do - expect_offense(<<~RUBY) - head :unprocessable_entity - ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. - RUBY - - expect_correction(<<~RUBY) - head :unprocessable_content - RUBY - end - - it 'registers an offense when using :unprocessable_entity in ternary expression' do - expect_offense(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_entity ? :unprocessable_content : :ok - ^^^^^^^^^^^^^^^^^^^^^ Use `:unprocessable_content` instead of `:unprocessable_entity`. The `:unprocessable_entity` status is deprecated. - RUBY - - expect_correction(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_content ? :unprocessable_content : :ok - RUBY - end - - it 'does not register an offense when using :unprocessable_content' do - expect_no_offenses(<<~RUBY) - render json: { error: 'Invalid data' }, status: :unprocessable_content - RUBY - end - - it 'does not register an offense when using :unprocessable_entity in hash key' do - expect_no_offenses(<<~RUBY) - { unprocessable_entity: 'Invalid data' } - RUBY - end - end -end