From f69ce7ce5dfa6421b53bad1cf19e75fe3c28b127 Mon Sep 17 00:00:00 2001 From: Tiago Cardoso Date: Wed, 13 May 2026 17:41:36 +0100 Subject: [PATCH] cast values to Enumerize::Value, filter invalid values on multiple this regression was caught while upgrading an application to rails 7.2, where activemodel with set the attributes API before enumerize is loaded, which makes the callback chain work differently when the model is assigned raw values which pass through `type.cast(value_before_type_cast)`, making it return the raw value, which can't respond to Enumerize::Value predication methods. --- lib/enumerize/activemodel.rb | 14 ++++++++++ test/activemodel_test.rb | 52 ++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/lib/enumerize/activemodel.rb b/lib/enumerize/activemodel.rb index b57a043..7f2ad16 100644 --- a/lib/enumerize/activemodel.rb +++ b/lib/enumerize/activemodel.rb @@ -50,6 +50,20 @@ def deserialize(value) @attr.find_value(value) end end + + def cast(value) + case value + when nil + return super + when Array + if @attr.arguments[:multiple] + found = @attr.find_values(*value) + return found.presence || super + end + end + + @attr.find_value(value) || value + end end end end diff --git a/test/activemodel_test.rb b/test/activemodel_test.rb index b2c2e52..4056bec 100644 --- a/test/activemodel_test.rb +++ b/test/activemodel_test.rb @@ -183,6 +183,58 @@ class InterestsRequiredActiveModelUser < ActiveModelUser expect(deserialized.map(&:to_s)).must_equal ['music', 'programming'] end end + + describe 'Type#cast' do + it 'casts single valid value to Enumerize::Value' do + type = model.attribute_types['sex'] + result = type.cast('male') + expect(result).must_be_instance_of Enumerize::Value + expect(result.to_s).must_equal 'male' + end + + it 'returns nil for nil single value' do + type = model.attribute_types['sex'] + result = type.cast(nil) + expect(result).must_be_nil + end + + it 'returns original value for invalid single value' do + type = model.attribute_types['sex'] + result = type.cast('invalid') + expect(result).must_equal 'invalid' + end + + it 'casts array of valid values for multiple attribute' do + type = model.attribute_types['interests'] + result = type.cast(['music', 'sports']) + expect(result).must_be_instance_of Array + expect(result.map(&:to_s)).must_equal ['music', 'sports'] + end + + it 'returns empty array as-is for multiple attribute' do + type = model.attribute_types['interests'] + result = type.cast([]) + expect(result).must_equal [] + end + + it 'filters out invalid values when at least one is valid' do + type = model.attribute_types['interests'] + result = type.cast(['music', 'invalid', 'sports']) + expect(result.map(&:to_s)).must_equal ['music', 'sports'] + end + + it 'returns array as-is when all values are invalid for multiple attribute' do + type = model.attribute_types['interests'] + result = type.cast(['invalid1', 'invalid2']) + expect(result).must_equal ['invalid1', 'invalid2'] + end + + it 'returns nil for nil value on multiple attribute' do + type = model.attribute_types['interests'] + result = type.cast(nil) + expect(result).must_be_nil + end + end end else