Skip to content

Don't nilify non-string values in case_insensitive_keys / strip_whitespace_keys#5841

Open
MahmoudBakr23 wants to merge 1 commit intoheartcombo:mainfrom
MahmoudBakr23:fix-case-insensitive-keys-non-string-values
Open

Don't nilify non-string values in case_insensitive_keys / strip_whitespace_keys#5841
MahmoudBakr23 wants to merge 1 commit intoheartcombo:mainfrom
MahmoudBakr23:fix-case-insensitive-keys-non-string-values

Conversation

@MahmoudBakr23
Copy link
Copy Markdown

What

When a non-string value (e.g. an integer column) is listed in config.case_insensitive_keys or config.strip_whitespace_keys, the value is silently overwritten with nil during before_validation.

Why

Authenticatable#apply_to_attribute_or_variable applies :downcase / :strip via .try(method). Object#try returns nil when the receiver doesn't respond to the method, and the result is then assigned back to the attribute. So an integer column listed in one of these keys gets nil-ified on every save attempt.

This was reported in #5780, where a typo in the config (%i[email, site_id], which parses to [:"email,", :site_id]) caused :site_id — an integer column — to end up in the list and silently get reset to nil. The misconfiguration is on the user side, but the failure mode is silent data loss rather than a no-op or a clear error, which is what makes it hard to debug (the reporter spent an hour tracing it).

Fix

Gate the assignment on respond_to? so a value that can't handle :downcase or :strip is left untouched:

self[attr] = self[attr].send(method) if self[attr].respond_to?(method)

Devise::ParameterFilter#filtered_hash_by_method_for_given_keys already takes the same approach on the params side, so this aligns the two paths.

Tests

Two tests in test/models/database_authenticatable_test.rb cover the case where an integer attribute (sign_in_count) is included in the keys list — they assert the value is preserved after valid? runs the before_validation :downcase_keys / :strip_whitespace callbacks. Both tests fail on main (the integer is replaced with nil) and pass with the fix.

Closes #5780.

…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 heartcombo#5780
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

Putting integer fields in config.case_insensitive_keys unsets them during update/validation

1 participant