Compare commits

...

7 Commits

Author SHA1 Message Date
Carlos Antonio da Silva
9932bc5364 Add changelog entry for rack error status 2025-12-31 10:30:44 -03:00
Carlos Antonio da Silva
3d3e75b49d Translate error status to code using Rails if available to avoid warning
Rack has deprecated `:unprocessable_entity` in favor of
`:unprocessable_content`, but the former has been used extensively
for years. Rails is now transparently converting that under the hood to
avoid the warnings, but our failure app wasn't going through the same
handling since it's more low level and responds to Rack directly. This
introduces the Rails translation handling if available on newer
versions, falling back to the Rack conversion which might emit the
warning if using `:unprocessable_entity` on Rack 3.1+

To fully fix it, people can configure their `error_status` to
`:unprocessable_content` on newer versions of Rack. The default for new
Devise apps will also change.

https://github.com/rack/rack/pull/2137
2025-12-31 10:26:02 -03:00
Carlos Antonio da Silva
f8b8092092 Add test for conditional error status 2025-12-31 10:25:57 -03:00
Carlos Antonio da Silva
9fa4d6389b Revert changes to controllers
We'll continue using `:unprocessable_entity` since Rails will
transparently convert this for us for the time being.
2025-12-31 10:05:53 -03:00
Carlos Antonio da Silva
9ac7f5395f Merge branch 'main' into update-rack-unprocessable_content 2025-12-31 09:41:29 -03:00
Taketo Takashima
e7f55961f2 Use :unprocessable_content in generated Devise config for Rack 3.1+
For rack 3.1 and higher, devise config uses `:unprocessable_content` instead of `:unprocessable_entity`.
For rack 3.0 and below, it continues to use `:unprocessable_entity`.
2025-09-12 19:27:55 +09:00
Taketo Takashima
ed625a804f Use Devise.responder.error_status instead of fixed :unprocessable_entity in confirmations and unlocks controllers 2025-09-12 14:54:00 +09:00
8 changed files with 19 additions and 8 deletions

View File

@@ -27,6 +27,9 @@
* enhancements
* Add Rails 8 support.
- 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)
* 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).
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.
* Add Ruby 3.4 and 4.0 support.
* 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)
* Password length validator is changed from

View File

@@ -493,7 +493,8 @@ Devise.setup do |config|
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
# these new defaults that match Hotwire/Turbo behavior.
# Note: These might become the new default in future versions of Devise.
config.responder.error_status = :unprocessable_entity
config.responder.error_status = :unprocessable_content # for Rack 3.1 or higher
# config.responder.error_status = :unprocessable_entity # for Rack 3.0 or lower
config.responder.redirect_status = :see_other
end
```

View File

@@ -27,7 +27,7 @@ class Devise::ConfirmationsController < DeviseController
set_flash_message!(:notice, :confirmed)
respond_with_navigational(resource){ redirect_to after_confirmation_path_for(resource_name, resource) }
else
# TODO: use `error_status` when the default changes to `:unprocessable_entity`.
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end

View File

@@ -29,7 +29,7 @@ class Devise::UnlocksController < DeviseController
set_flash_message! :notice, :unlocked
respond_with_navigational(resource){ redirect_to after_unlock_path_for(resource) }
else
# TODO: use `error_status` when the default changes to `:unprocessable_entity`.
# TODO: use `error_status` when the default changes to `:unprocessable_entity` / `:unprocessable_content`.
respond_with_navigational(resource.errors, status: :unprocessable_entity){ render :new }
end
end

View File

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

View File

@@ -305,7 +305,7 @@ Devise.setup do |config|
# apps is `200 OK` and `302 Found` respectively, but new apps are generated with
# these new defaults that match Hotwire/Turbo behavior.
# Note: These might become the new default in future versions of Devise.
config.responder.error_status = :unprocessable_entity
config.responder.error_status = <%= Rack::Utils::SYMBOL_TO_STATUS_CODE.key(422).inspect %>
config.responder.redirect_status = :see_other
# ==> Configuration for :registerable

View File

@@ -37,5 +37,4 @@ class DeviseGeneratorTest < Rails::Generators::TestCase
FileUtils.mkdir_p(destination)
FileUtils.cp routes, destination
end
end

View File

@@ -23,4 +23,12 @@ class InstallGeneratorTest < Rails::Generators::TestCase
assert_no_file "config/initializers/devise.rb"
assert_no_file "config/locales/devise.en.yml"
end
test "responder error_status based on rack version" do
run_generator(["--orm=active_record"])
error_status = Rack::VERSION >= "3.1" ? :unprocessable_content : :unprocessable_entity
assert_file "config/initializers/devise.rb", /config\.responder\.error_status = #{error_status.inspect}/
end
end