Skip to content

Commit 438cad4

Browse files
authored
Merge pull request rails#50090 from fatkodima/fix-active_job-serialization-string-subclasses
Fix ActiveJob arguments serialization to correctly serialize String subclasses having custom serializers
2 parents 6178b8b + 14578ea commit 438cad4

File tree

2 files changed

+47
-11
lines changed

2 files changed

+47
-11
lines changed

activejob/lib/active_job/arguments.rb

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,6 @@ def deserialize(arguments)
4646
end
4747

4848
private
49-
# :nodoc:
50-
PERMITTED_TYPES = [ NilClass, String, Integer, Float, TrueClass, FalseClass ]
5149
# :nodoc:
5250
GLOBALID_KEY = "_aj_globalid"
5351
# :nodoc:
@@ -67,13 +65,19 @@ def deserialize(arguments)
6765
OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym,
6866
WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym,
6967
]
70-
private_constant :PERMITTED_TYPES, :RESERVED_KEYS, :GLOBALID_KEY,
68+
private_constant :RESERVED_KEYS, :GLOBALID_KEY,
7169
:SYMBOL_KEYS_KEY, :RUBY2_KEYWORDS_KEY, :WITH_INDIFFERENT_ACCESS_KEY
7270

7371
def serialize_argument(argument)
7472
case argument
75-
when *PERMITTED_TYPES
73+
when nil, true, false, Integer, Float # Types that can hardly be subclassed
7674
argument
75+
when String
76+
if argument.class == String
77+
argument
78+
else
79+
Serializers.serialize(argument)
80+
end
7781
when GlobalID::Identification
7882
convert_to_global_id_hash(argument)
7983
when Array
@@ -90,27 +94,27 @@ def serialize_argument(argument)
9094
result = serialize_hash(argument)
9195
result[aj_hash_key] = symbol_keys
9296
result
93-
when -> (arg) { arg.respond_to?(:permitted?) && arg.respond_to?(:to_h) }
94-
serialize_indifferent_hash(argument.to_h)
9597
else
96-
if BigDecimal === argument && !ActiveJob.use_big_decimal_serializer
98+
if argument.respond_to?(:permitted?) && argument.respond_to?(:to_h)
99+
serialize_indifferent_hash(argument.to_h)
100+
elsif BigDecimal === argument && !ActiveJob.use_big_decimal_serializer
97101
ActiveJob.deprecator.warn(<<~MSG)
98102
Primitive serialization of BigDecimal job arguments is deprecated as it may serialize via .to_s using certain queue adapters.
99103
Enable config.active_job.use_big_decimal_serializer to use BigDecimalSerializer instead, which will be mandatory in Rails 7.2.
100104
101105
Note that if your application has multiple replicas, you should only enable this setting after successfully deploying your app to Rails 7.1 first.
102106
This will ensure that during your deployment all replicas are capable of deserializing arguments serialized with BigDecimalSerializer.
103107
MSG
104-
return argument
108+
argument
109+
else
110+
Serializers.serialize(argument)
105111
end
106-
107-
Serializers.serialize(argument)
108112
end
109113
end
110114

111115
def deserialize_argument(argument)
112116
case argument
113-
when *PERMITTED_TYPES
117+
when nil, true, false, String, Integer, Float
114118
argument
115119
when BigDecimal # BigDecimal may have been legacy serialized; Remove in 7.2
116120
argument

activejob/test/cases/argument_serialization_test.rb

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
# frozen_string_literal: true
22

3+
require "json"
34
require "bigdecimal"
45
require "helper"
56
require "active_job/arguments"
@@ -23,6 +24,24 @@ def self.permitted?
2324
end
2425
end
2526

27+
class MyString < String
28+
end
29+
30+
class MyStringSerializer < ActiveJob::Serializers::ObjectSerializer
31+
def serialize(argument)
32+
super({ "value" => argument.to_s })
33+
end
34+
35+
def deserialize(hash)
36+
MyString.new(hash["value"])
37+
end
38+
39+
private
40+
def klass
41+
MyString
42+
end
43+
end
44+
2645
setup do
2746
@person = Person.find("5")
2847
end
@@ -124,6 +143,19 @@ def self.permitted?
124143
assert_arguments_unchanged MyClassWithPermitted
125144
end
126145

146+
test "serialize a String subclass object" do
147+
original_serializers = ActiveJob::Serializers.serializers
148+
ActiveJob::Serializers.add_serializers(MyStringSerializer)
149+
150+
my_string = MyString.new("foo")
151+
serialized = ActiveJob::Arguments.serialize([my_string])
152+
deserialized = ActiveJob::Arguments.deserialize(JSON.load(JSON.dump(serialized))).first
153+
assert_instance_of MyString, deserialized
154+
assert_equal my_string, deserialized
155+
ensure
156+
ActiveJob::Serializers._additional_serializers = original_serializers
157+
end
158+
127159
test "serialize a hash" do
128160
symbol_key = { a: 1 }
129161
string_key = { "a" => 1 }

0 commit comments

Comments
 (0)