From 1ca41981d4ad83a8891b38f386ab326bbbac5ed5 Mon Sep 17 00:00:00 2001 From: Mahmoud Bakr Date: Sun, 26 Apr 2026 22:30:11 +0300 Subject: [PATCH] Skip non-responding values in case_insensitive_keys/strip_whitespace_keys Previously, apply_to_attribute_or_variable used .try(method) to apply :downcase or :strip to each configured key. When the value did not respond to the method (e.g. an Integer column accidentally listed in config.case_insensitive_keys), .try returned nil and that nil was written back, silently overwriting the column. Gate the assignment on respond_to? so a non-responding value is left untouched. This matches what Devise::ParameterFilter already does for the same keys on the params side. Closes #5780 --- lib/devise/models/authenticatable.rb | 6 +++--- test/models/database_authenticatable_test.rb | 18 ++++++++++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/lib/devise/models/authenticatable.rb b/lib/devise/models/authenticatable.rb index df964537ea..1b26ad5cf3 100644 --- a/lib/devise/models/authenticatable.rb +++ b/lib/devise/models/authenticatable.rb @@ -205,15 +205,15 @@ def strip_whitespace def apply_to_attribute_or_variable(attr, method) if self[attr] - self[attr] = self[attr].try(method) + self[attr] = self[attr].send(method) if self[attr].respond_to?(method) # Use respond_to? here to avoid a regression where globally # configured strip_whitespace_keys or case_insensitive_keys were # attempting to strip or downcase when a model didn't have the # globally configured key. elsif respond_to?(attr) && respond_to?("#{attr}=") - new_value = send(attr).try(method) - send("#{attr}=", new_value) + value = send(attr) + send("#{attr}=", value.send(method)) if value.respond_to?(method) end end diff --git a/test/models/database_authenticatable_test.rb b/test/models/database_authenticatable_test.rb index 909e010458..2c320be538 100644 --- a/test/models/database_authenticatable_test.rb +++ b/test/models/database_authenticatable_test.rb @@ -70,6 +70,24 @@ def setup end end + test "does not nilify case_insensitive_keys whose value does not respond to downcase" do + swap Devise, case_insensitive_keys: [:email, :sign_in_count] do + user = create_user + user.sign_in_count = 12 + user.valid? + assert_equal 12, user.sign_in_count + end + end + + test "does not nilify strip_whitespace_keys whose value does not respond to strip" do + swap Devise, strip_whitespace_keys: [:email, :sign_in_count] do + user = create_user + user.sign_in_count = 12 + user.valid? + assert_equal 12, user.sign_in_count + end + end + test "param filter should not convert booleans and integer to strings" do conditions = { "login" => "foo@bar.com", "bool1" => true, "bool2" => false, "fixnum" => 123, "will_be_converted" => (1..10) } conditions = Devise::ParameterFilter.new([], []).filter(conditions)