diff --git a/app/controllers/devise/confirmations_controller.rb b/app/controllers/devise/confirmations_controller.rb index 3069c6efbf..c69a997609 100644 --- a/app/controllers/devise/confirmations_controller.rb +++ b/app/controllers/devise/confirmations_controller.rb @@ -14,7 +14,7 @@ def create if successfully_sent?(resource) respond_with({}, location: after_resending_confirmation_instructions_path_for(resource_name)) else - respond_with(resource) + respond_with resource, status: :unprocessable_entity end end diff --git a/app/controllers/devise/passwords_controller.rb b/app/controllers/devise/passwords_controller.rb index 64c2e2f858..f51b69928d 100644 --- a/app/controllers/devise/passwords_controller.rb +++ b/app/controllers/devise/passwords_controller.rb @@ -18,7 +18,7 @@ def create if successfully_sent?(resource) respond_with({}, location: after_sending_reset_password_instructions_path_for(resource_name)) else - respond_with(resource) + respond_with resource, status: :unprocessable_entity end end @@ -44,10 +44,10 @@ def update else set_flash_message!(:notice, :updated_not_active) end - respond_with resource, location: after_resetting_password_path_for(resource) + respond_with resource, location: after_resetting_password_path_for(resource), status: :see_other else set_minimum_password_length - respond_with resource + respond_with resource, status: :unprocessable_entity end end diff --git a/app/controllers/devise/registrations_controller.rb b/app/controllers/devise/registrations_controller.rb index 1b8a969f82..4fcd03380f 100644 --- a/app/controllers/devise/registrations_controller.rb +++ b/app/controllers/devise/registrations_controller.rb @@ -31,7 +31,7 @@ def create else clean_up_passwords resource set_minimum_password_length - respond_with resource + respond_with resource, status: :unprocessable_entity end end @@ -53,11 +53,11 @@ def update set_flash_message_for_update(resource, prev_unconfirmed_email) bypass_sign_in resource, scope: resource_name if sign_in_after_change_password? - respond_with resource, location: after_update_path_for(resource) + respond_with resource, location: after_update_path_for(resource), status: :see_other else clean_up_passwords resource set_minimum_password_length - respond_with resource + respond_with resource, status: :unprocessable_entity end end @@ -67,7 +67,7 @@ def destroy Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name) set_flash_message! :notice, :destroyed yield resource if block_given? - respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name) } + respond_with_navigational(resource){ redirect_to after_sign_out_path_for(resource_name), status: :see_other } end # GET /resource/cancel diff --git a/app/controllers/devise/sessions_controller.rb b/app/controllers/devise/sessions_controller.rb index 9090b002f3..2250104418 100644 --- a/app/controllers/devise/sessions_controller.rb +++ b/app/controllers/devise/sessions_controller.rb @@ -77,7 +77,7 @@ def respond_to_on_destroy # support returning empty response on GET request respond_to do |format| format.all { head :no_content } - format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name) } + format.any(*navigational_formats) { redirect_to after_sign_out_path_for(resource_name), status: :see_other } end end end diff --git a/app/controllers/devise/unlocks_controller.rb b/app/controllers/devise/unlocks_controller.rb index 1d04d62274..93f87ad3e3 100644 --- a/app/controllers/devise/unlocks_controller.rb +++ b/app/controllers/devise/unlocks_controller.rb @@ -16,7 +16,7 @@ def create if successfully_sent?(resource) respond_with({}, location: after_sending_unlock_instructions_path_for(resource)) else - respond_with(resource) + respond_with resource, status: :unprocessable_entity end end diff --git a/app/views/devise/registrations/edit.html.erb b/app/views/devise/registrations/edit.html.erb index 38d95b85a8..2a666e9257 100644 --- a/app/views/devise/registrations/edit.html.erb +++ b/app/views/devise/registrations/edit.html.erb @@ -38,6 +38,6 @@
Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
+Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
<%= link_to "Back", :back %> diff --git a/app/views/devise/shared/_links.html.erb b/app/views/devise/shared/_links.html.erb index 96a9412417..7a75304bad 100644 --- a/app/views/devise/shared/_links.html.erb +++ b/app/views/devise/shared/_links.html.erb @@ -20,6 +20,6 @@ <%- if devise_mapping.omniauthable? %> <%- resource_class.omniauth_providers.each do |provider| %> - <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider), method: :post %>Unhappy? <%= link_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>
+Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?", turbo_confirm: "Are you sure?" }, method: :delete %>
<%= link_to "Back", :back %> diff --git a/test/failure_app_test.rb b/test/failure_app_test.rb index 883cf8b9bd..3a97916e8a 100644 --- a/test/failure_app_test.rb +++ b/test/failure_app_test.rb @@ -2,6 +2,7 @@ require 'test_helper' require 'ostruct' +require 'minitest/mock' class FailureTest < ActiveSupport::TestCase class RootFailureApp < Devise::FailureApp @@ -65,6 +66,10 @@ def fake_engine end end + class SessionStorableFailureApp < Devise::FailureApp + def store_location_for(*); end + end + class RequestWithoutFlashSupport < ActionDispatch::Request undef_method :flash end @@ -355,6 +360,20 @@ def call_failure(env_params = {}) assert_includes @response.third.body, 'Your account is not activated yet.' end + test 'returns to the default redirect location for turbo_stream' do + Mime::Type.register "text/vnd.turbo-stream.html", :turbo_stream + env = { + "warden.options" => { recall: "devise/sessions#new", attempted_path: "/users/sign_in" }, + "devise.mapping" => Devise.mappings[:user], + "warden" => stub_everything, + "formats" => Mime[:turbo_stream], + app: SessionStorableFailureApp + } + call_failure(env) + assert_equal 302, @response.first + assert_equal 'http://test.host/users/sign_in', @response.second['Location'] + end + if Rails.application.config.respond_to?(:relative_url_root) test 'calls the original controller with the proper environment considering the relative url root' do swap Rails.application.config, relative_url_root: "/sample" do diff --git a/test/integration/authenticatable_test.rb b/test/integration/authenticatable_test.rb index 6c3be3b57c..b1f670b4a5 100644 --- a/test/integration/authenticatable_test.rb +++ b/test/integration/authenticatable_test.rb @@ -119,7 +119,7 @@ class AuthenticationSanityTest < Devise::IntegrationTest delete destroy_admin_session_path assert_response :redirect - assert_redirected_to root_path + assert_see_other_to root_path get root_path assert_contain 'Signed out successfully' @@ -129,7 +129,7 @@ class AuthenticationSanityTest < Devise::IntegrationTest test 'unauthenticated admin set message on sign out' do delete destroy_admin_session_path assert_response :redirect - assert_redirected_to root_path + assert_see_other_to root_path get root_path assert_contain 'Signed out successfully' diff --git a/test/integration/omniauthable_test.rb b/test/integration/omniauthable_test.rb index 1b14911dab..89b668178c 100644 --- a/test/integration/omniauthable_test.rb +++ b/test/integration/omniauthable_test.rb @@ -126,15 +126,19 @@ def stub_action!(name) end end - test "generates a link to authenticate with provider" do + test "generates a button to authenticate with provider" do visit "/users/sign_in" - assert_select "a[href=?][data-method='post']", "/users/auth/facebook", text: "Sign in with FaceBook" + assert_select "form[action=?]", "/users/auth/facebook" do + assert_select "input[value=?]", "Sign in with FaceBook" + end end - test "generates a proper link when SCRIPT_NAME is set" do + test "generates a proper button when SCRIPT_NAME is set" do header 'SCRIPT_NAME', '/q' visit "/users/sign_in" - assert_select "a[href=?][data-method='post']", "/q/users/auth/facebook", text: "Sign in with FaceBook" + assert_select "form[action=?]", "/q/users/auth/facebook" do + assert_select "input[value=?]", "Sign in with FaceBook" + end end test "handles callback error parameter according to the specification" do diff --git a/test/integration/recoverable_test.rb b/test/integration/recoverable_test.rb index 7626607816..4aee813496 100644 --- a/test/integration/recoverable_test.rb +++ b/test/integration/recoverable_test.rb @@ -76,7 +76,7 @@ def reset_password(options = {}, &block) fill_in 'email', with: 'foo@bar.com' end - assert_response :success + assert_response :unprocessable_entity assert_current_url '/users/password' assert_have_selector "input[type=email][value='foo@bar.com']" assert_contain 'not found' @@ -102,7 +102,7 @@ def reset_password(options = {}, &block) fill_in 'email', with: ' foo@bar.com ' end - assert_response :success + assert_response :unprocessable_entity assert_current_url '/users/password' assert_have_selector "input[type=email][value=' foo@bar.com ']" assert_contain 'not found' @@ -132,7 +132,7 @@ def reset_password(options = {}, &block) fill_in 'email', with: 'invalid.test@test.com' end - assert_response :success + assert_response :unprocessable_entity assert_current_url '/users/password' assert_have_selector "input[type=email][value='invalid.test@test.com']" assert_contain 'not found' @@ -156,7 +156,7 @@ def reset_password(options = {}, &block) user = create_user reset_password reset_password_token: 'invalid_reset_password' - assert_response :success + assert_response :unprocessable_entity assert_current_url '/users/password' assert_have_selector '#error_explanation' assert_contain %r{Reset password token(.*)invalid} @@ -170,7 +170,7 @@ def reset_password(options = {}, &block) fill_in 'Confirm new password', with: 'other_password' end - assert_response :success + assert_response :unprocessable_entity assert_current_url '/users/password' assert_have_selector '#error_explanation' assert_contain "Password confirmation doesn't match Password" @@ -192,7 +192,7 @@ def reset_password(options = {}, &block) request_forgot_password reset_password { fill_in 'Confirm new password', with: 'other_password' } - assert_response :success + assert_response :unprocessable_entity assert_have_selector '#error_explanation' refute user.reload.valid_password?('987654321') diff --git a/test/integration/timeoutable_test.rb b/test/integration/timeoutable_test.rb index b6f2471480..32c44bc6d2 100644 --- a/test/integration/timeoutable_test.rb +++ b/test/integration/timeoutable_test.rb @@ -94,7 +94,7 @@ def last_request_at delete destroy_user_session_path assert_response :redirect - assert_redirected_to root_path + assert_see_other_to root_path follow_redirect! assert_contain 'Signed out successfully' end @@ -109,7 +109,7 @@ def last_request_at follow_redirect! assert_response :success - assert_contain 'Sign in' + assert_contain 'Log in' refute warden.authenticated?(:user) end diff --git a/test/support/http_method_compatibility.rb b/test/support/http_method_compatibility.rb index f901ad858d..81da9d1170 100644 --- a/test/support/http_method_compatibility.rb +++ b/test/support/http_method_compatibility.rb @@ -16,6 +16,13 @@ class IntegrationTest < ActionDispatch::IntegrationTest end end end + + def assert_see_other_to(url) + assert_equal 303, @integration_session.status, + "Expected status to be 303, got #{@integration_session.status}" + + assert_url url, @integration_session.headers["Location"] + end end class ControllerTestCase < ActionController::TestCase