From c79c421b89ffebf5f7590c2ea4e53b643b89be22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A2u=20Cao?= Date: Mon, 10 Aug 2026 16:37:01 -0600 Subject: [PATCH] Fix Devise Turbo Stream responses for flash messages Wire Users::DeviseController as Devise parent controller with the Turbo-aware responder, so failed form submissions (login, password reset) render correctly as HTML with 422 status instead of unprocessable turbo-stream content that Turbo silently drops. Also fixes a NameError in the responder (rendering_options -> error_rendering_options) and removes the dead TurboController. --- app/controllers/turbo_controller.rb | 18 ------------------ app/controllers/users/devise_controller.rb | 2 +- config/initializers/devise.rb | 8 ++++++++ 3 files changed, 9 insertions(+), 19 deletions(-) delete mode 100644 app/controllers/turbo_controller.rb diff --git a/app/controllers/turbo_controller.rb b/app/controllers/turbo_controller.rb deleted file mode 100644 index 600e9d2..0000000 --- a/app/controllers/turbo_controller.rb +++ /dev/null @@ -1,18 +0,0 @@ -class TurboController < ApplicationController - class Responder < ActionController::Responder - def to_turbo_stream - controller.render(options.merge(formats: :html)) - rescue ActionView::MissingTemplate => error - if get? - raise error - elsif has_errors? && default_action - render rendering_options.merge(formats: :html, status: :unprocessable_entity) - else - redirect_to navigation_location - end - end - end - - self.responder = Responder - respond_to :html, :turbo_stream -end diff --git a/app/controllers/users/devise_controller.rb b/app/controllers/users/devise_controller.rb index c3aafd5..13b058d 100644 --- a/app/controllers/users/devise_controller.rb +++ b/app/controllers/users/devise_controller.rb @@ -6,7 +6,7 @@ class Users::DeviseController < ApplicationController if get? raise error elsif has_errors? && default_action - render rendering_options.merge(formats: :html, status: :unprocessable_entity) + render error_rendering_options.merge(formats: :html, status: :unprocessable_entity) else redirect_to navigation_location end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index f87b296..c4931b1 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -6,6 +6,7 @@ require 'securerandom' # Many of these configuration options can be set straight in your model. Devise.setup do |config| # Hotwire/Turbo + config.parent_controller = 'Users::DeviseController' config.responder.error_status = :unprocessable_entity config.responder.redirect_status = :see_other @@ -324,3 +325,10 @@ Devise.setup do |config| # changed. Defaults to true, so a user is signed in automatically after changing a password. # config.sign_in_after_change_password = true end + +# Turbo-aware responder for Devise controllers +ActiveSupport.on_load(:devise_controller) do + self.responder = Users::DeviseController::Responder + Users::DeviseController::Responder.error_status = :unprocessable_entity + Users::DeviseController::Responder.redirect_status = :see_other +end