From e4d0fb5fa3b1faf025f9844ce4142808e6739405 Mon Sep 17 00:00:00 2001 From: Geoff Harcourt Date: Fri, 6 Nov 2020 12:53:16 -0500 Subject: [PATCH] Allow wrapping of lockable Warden after sign-in hook in proc For applications using a primary/replica multiple database setup, Rails 6's default connection switching can lead to the `Lockable` after sign-in hook firing on `GET` requests, getting the read-only database, and then attempting to write while zeroing out the user's failed attempts. This change adds a customizable wrapper proc that can allow applications to customize this behavior. For a primary/replica setup using ActiveRecord's default connection switching, it might look like this: ```ruby Devise.setup do |config| config.warden_hook_save_wrapper = Proc.new { # Use the writable DB connection no matter what ApplicationRecord.connected_to(role: :writing) do yield end } end ``` Fix #5264 --- lib/devise.rb | 3 +++ lib/devise/hooks/lockable.rb | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/lib/devise.rb b/lib/devise.rb index 0451876df9..79eea7e985 100644 --- a/lib/devise.rb +++ b/lib/devise.rb @@ -297,6 +297,9 @@ module Test mattr_accessor :sign_in_after_change_password @@sign_in_after_change_password = true + mattr_accessor :warden_hook_save_wrapper + @@warden_hook_save_wrapper = Proc.new { yield } + def self.activerecord51? # :nodoc: defined?(ActiveRecord) && ActiveRecord.gem_version >= Gem::Version.new("5.1.x") end diff --git a/lib/devise/hooks/lockable.rb b/lib/devise/hooks/lockable.rb index a73a1752e2..9c55847c55 100644 --- a/lib/devise/hooks/lockable.rb +++ b/lib/devise/hooks/lockable.rb @@ -5,8 +5,10 @@ Warden::Manager.after_set_user except: :fetch do |record, warden, options| if record.respond_to?(:failed_attempts) && warden.authenticated?(options[:scope]) unless record.failed_attempts.to_i.zero? - record.failed_attempts = 0 - record.save(validate: false) + Devise.warden_hook_save_wrapper do + record.failed_attempts = 0 + record.save(validate: false) + end end end end