mirror of https://github.com/rails/rails
Fix ActiveJob arguments serialization to correctly serialize String subclasses having custom serializers
Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
This commit is contained in:
parent
e514c586f1
commit
14578eaa4f
|
@ -46,8 +46,6 @@ module ActiveJob
|
|||
end
|
||||
|
||||
private
|
||||
# :nodoc:
|
||||
PERMITTED_TYPES = [ NilClass, String, Integer, Float, TrueClass, FalseClass ]
|
||||
# :nodoc:
|
||||
GLOBALID_KEY = "_aj_globalid"
|
||||
# :nodoc:
|
||||
|
@ -67,13 +65,19 @@ module ActiveJob
|
|||
OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym,
|
||||
WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_KEY.to_sym,
|
||||
]
|
||||
private_constant :PERMITTED_TYPES, :RESERVED_KEYS, :GLOBALID_KEY,
|
||||
private_constant :RESERVED_KEYS, :GLOBALID_KEY,
|
||||
:SYMBOL_KEYS_KEY, :RUBY2_KEYWORDS_KEY, :WITH_INDIFFERENT_ACCESS_KEY
|
||||
|
||||
def serialize_argument(argument)
|
||||
case argument
|
||||
when *PERMITTED_TYPES
|
||||
when nil, true, false, Integer, Float # Types that can hardly be subclassed
|
||||
argument
|
||||
when String
|
||||
if argument.class == String
|
||||
argument
|
||||
else
|
||||
Serializers.serialize(argument)
|
||||
end
|
||||
when GlobalID::Identification
|
||||
convert_to_global_id_hash(argument)
|
||||
when Array
|
||||
|
@ -90,10 +94,10 @@ module ActiveJob
|
|||
result = serialize_hash(argument)
|
||||
result[aj_hash_key] = symbol_keys
|
||||
result
|
||||
when -> (arg) { arg.respond_to?(:permitted?) && arg.respond_to?(:to_h) }
|
||||
serialize_indifferent_hash(argument.to_h)
|
||||
else
|
||||
if BigDecimal === argument && !ActiveJob.use_big_decimal_serializer
|
||||
if argument.respond_to?(:permitted?) && argument.respond_to?(:to_h)
|
||||
serialize_indifferent_hash(argument.to_h)
|
||||
elsif BigDecimal === argument && !ActiveJob.use_big_decimal_serializer
|
||||
ActiveJob.deprecator.warn(<<~MSG)
|
||||
Primitive serialization of BigDecimal job arguments is deprecated as it may serialize via .to_s using certain queue adapters.
|
||||
Enable config.active_job.use_big_decimal_serializer to use BigDecimalSerializer instead, which will be mandatory in Rails 7.2.
|
||||
|
@ -101,16 +105,16 @@ module ActiveJob
|
|||
Note that if your application has multiple replicas, you should only enable this setting after successfully deploying your app to Rails 7.1 first.
|
||||
This will ensure that during your deployment all replicas are capable of deserializing arguments serialized with BigDecimalSerializer.
|
||||
MSG
|
||||
return argument
|
||||
end
|
||||
|
||||
argument
|
||||
else
|
||||
Serializers.serialize(argument)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def deserialize_argument(argument)
|
||||
case argument
|
||||
when *PERMITTED_TYPES
|
||||
when nil, true, false, String, Integer, Float
|
||||
argument
|
||||
when BigDecimal # BigDecimal may have been legacy serialized; Remove in 7.2
|
||||
argument
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "json"
|
||||
require "bigdecimal"
|
||||
require "helper"
|
||||
require "active_job/arguments"
|
||||
|
@ -23,6 +24,24 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
|||
end
|
||||
end
|
||||
|
||||
class MyString < String
|
||||
end
|
||||
|
||||
class MyStringSerializer < ActiveJob::Serializers::ObjectSerializer
|
||||
def serialize(argument)
|
||||
super({ "value" => argument.to_s })
|
||||
end
|
||||
|
||||
def deserialize(hash)
|
||||
MyString.new(hash["value"])
|
||||
end
|
||||
|
||||
private
|
||||
def klass
|
||||
MyString
|
||||
end
|
||||
end
|
||||
|
||||
setup do
|
||||
@person = Person.find("5")
|
||||
end
|
||||
|
@ -124,6 +143,19 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
|||
assert_arguments_unchanged MyClassWithPermitted
|
||||
end
|
||||
|
||||
test "serialize a String subclass object" do
|
||||
original_serializers = ActiveJob::Serializers.serializers
|
||||
ActiveJob::Serializers.add_serializers(MyStringSerializer)
|
||||
|
||||
my_string = MyString.new("foo")
|
||||
serialized = ActiveJob::Arguments.serialize([my_string])
|
||||
deserialized = ActiveJob::Arguments.deserialize(JSON.load(JSON.dump(serialized))).first
|
||||
assert_instance_of MyString, deserialized
|
||||
assert_equal my_string, deserialized
|
||||
ensure
|
||||
ActiveJob::Serializers._additional_serializers = original_serializers
|
||||
end
|
||||
|
||||
test "serialize a hash" do
|
||||
symbol_key = { a: 1 }
|
||||
string_key = { "a" => 1 }
|
||||
|
|
Loading…
Reference in New Issue