Skip to content

Commit 8054ad5

Browse files
authored
Use :unprocessable_content in generated Devise config for Rack 3.1+, avoid Rack warnings (#5797)
In Rack v3.1.0, the symbol for HTTP status code 422 was changed from `:unprocessable_entity` to `:unprocessable_content`. As a result, when using rack 3.2 with the following configuration in `config/initializers/devise.rb`, a warning is shown on login failure: ```ruby # config/initializers/devise.rb Devise.setup do |config| ... config.responder.error_status = :unprocessable_entity ``` Warning message: ```sh /path-to-app/vendor/bundle/ruby/3.4.0/gems/devise-4.9.4/lib/devise/failure_app.rb:80: warning: Status code :unprocessable_entity is deprecated and will be removed in a future version of Rack. Please use :unprocessable_content instead. ``` This warning can be resolved by updating the config as follows: ```diff # config/initializers/devise.rb Devise.setup do |config| ... + config.responder.error_status = :unprocessable_content - config.responder.error_status = :unprocessable_entity ``` This fixes the root cause of the warning for new apps by adjusting the generated config during `$ rails generate devise:install` depending on the rack version, so new apps using newer Rack versions generate `error_status = :unprocessable_content` instead of `:unprocessable_entity`. Existing apps are handled by [latest versions of Rails, which will now transparently convert the code under the hood to avoid the Rack warning](rails/rails#53383), and Devise will use that translation layer when available in the failure app to prevent the warning there as well (since that isn't covered by Rails automatic conversion). Signed-off-by: Carlos Antonio da Silva <[email protected]>
1 parent d13ef89 commit 8054ad5

File tree

8 files changed

+19
-8
lines changed

8 files changed

+19
-8
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
* enhancements
2828
* Add Rails 8 support.
2929
- Routes are lazy-loaded by default in test and development environments now so Devise loads them before `Devise.mappings` call. [#5728](https://github.com/heartcombo/devise/pull/5728)
30+
* New apps using Rack 3.1+ will be generated using `config.responder.error_status = :unprocessable_content`, since [`:unprocessable_entity` has been deprecated by Rack](https://github.com/rack/rack/pull/2137).
31+
32+
Latest versions of [Rails transparently convert `:unprocessable_entity` -> `:unprocessable_content`](https://github.com/rails/rails/pull/53383), and Devise will use that in the failure app to avoid Rack deprecation warnings for apps that are configured with `:unprocessable_entity`. They can also simply change their `error_status` to `:unprocessable_content` in latest Rack versions to avoid the warning.
3033
* Add Ruby 3.4 and 4.0 support.
3134
* Reenable Mongoid test suite across all Rails 7+ versions, to ensure we continue supporting it. Changes to dirty tracking to support Mongoid 8.0+. [#5568](https://github.com/heartcombo/devise/pull/5568)
3235
* Password length validator is changed from

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -493,7 +493,8 @@ Devise.setup do |config|
493493
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
494494
# these new defaults that match Hotwire/Turbo behavior.
495495
# Note: These might become the new default in future versions of Devise.
496-
config.responder.error_status = :unprocessable_entity
496+
config.responder.error_status = :unprocessable_content # for Rack 3.1 or higher
497+
# config.responder.error_status = :unprocessable_entity # for Rack 3.0 or lower
497498
config.responder.redirect_status = :see_other
498499
end
499500
```

app/controllers/devise/confirmations_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ def show
2727
set_flash_message!(:notice, :confirmed)
2828
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
2929
else
30-
# TODO: use `error_status` when the default changes to `:unprocessable_entity`.
30+
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
3131
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
3232
end
3333
end

app/controllers/devise/unlocks_controller.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def show
2929
set_flash_message! :notice, :unlocked
3030
respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
3131
else
32-
# TODO: use `error_status` when the default changes to `:unprocessable_entity`.
32+
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
3333
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
3434
end
3535
end

lib/devise/failure_app.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -77,9 +77,9 @@ def recall
7777

7878
flash.now[:alert] = i18n_message(:invalid) if is_flashing_format?
7979
self.response = recall_app(warden_options[:recall]).call(request.env).tap { |response|
80-
response[0] = Rack::Utils.status_code(
81-
response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
82-
)
80+
status = response[0].in?(300..399) ? Devise.responder.redirect_status : Devise.responder.error_status
81+
# Avoid warnings translating status to code using Rails if available (e.g. `unprocessable_entity` => `unprocessable_content`)
82+
response[0] = ActionDispatch::Response.try(:rack_status_code, status) || Rack::Utils.status_code(status)
8383
}
8484
end
8585

lib/generators/templates/devise.rb

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@
305305
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
306306
# these new defaults that match Hotwire/Turbo behavior.
307307
# Note: These might become the new default in future versions of Devise.
308-
config.responder.error_status = :unprocessable_entity
308+
config.responder.error_status = <%= Rack::Utils::SYMBOL_TO_STATUS_CODE.key(422).inspect %>
309309
config.responder.redirect_status = :see_other
310310
311311
# ==> Configuration for :registerable

test/generators/devise_generator_test.rb

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,5 +37,4 @@ def copy_routes
3737
FileUtils.mkdir_p(destination)
3838
FileUtils.cp routes, destination
3939
end
40-
4140
end

test/generators/install_generator_test.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,12 @@ class InstallGeneratorTest < Rails::Generators::TestCase
2323
assert_no_file "config/initializers/devise.rb"
2424
assert_no_file "config/locales/devise.en.yml"
2525
end
26+
27+
test "responder error_status based on rack version" do
28+
run_generator(["--orm=active_record"])
29+
30+
error_status = Rack::RELEASE >= "3.1" ? :unprocessable_content : :unprocessable_entity
31+
32+
assert_file "config/initializers/devise.rb", /config\.responder\.error_status = #{error_status.inspect}/
33+
end
2634
end

0 commit comments

Comments
 (0)