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
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
# :nodoc:
|
|
||||||
PERMITTED_TYPES = [ NilClass, String, Integer, Float, TrueClass, FalseClass ]
|
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
GLOBALID_KEY = "_aj_globalid"
|
GLOBALID_KEY = "_aj_globalid"
|
||||||
# :nodoc:
|
# :nodoc:
|
||||||
|
@ -67,13 +65,19 @@ module ActiveJob
|
||||||
OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym,
|
OBJECT_SERIALIZER_KEY, OBJECT_SERIALIZER_KEY.to_sym,
|
||||||
WITH_INDIFFERENT_ACCESS_KEY, WITH_INDIFFERENT_ACCESS_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
|
:SYMBOL_KEYS_KEY, :RUBY2_KEYWORDS_KEY, :WITH_INDIFFERENT_ACCESS_KEY
|
||||||
|
|
||||||
def serialize_argument(argument)
|
def serialize_argument(argument)
|
||||||
case argument
|
case argument
|
||||||
when *PERMITTED_TYPES
|
when nil, true, false, Integer, Float # Types that can hardly be subclassed
|
||||||
argument
|
argument
|
||||||
|
when String
|
||||||
|
if argument.class == String
|
||||||
|
argument
|
||||||
|
else
|
||||||
|
Serializers.serialize(argument)
|
||||||
|
end
|
||||||
when GlobalID::Identification
|
when GlobalID::Identification
|
||||||
convert_to_global_id_hash(argument)
|
convert_to_global_id_hash(argument)
|
||||||
when Array
|
when Array
|
||||||
|
@ -90,10 +94,10 @@ module ActiveJob
|
||||||
result = serialize_hash(argument)
|
result = serialize_hash(argument)
|
||||||
result[aj_hash_key] = symbol_keys
|
result[aj_hash_key] = symbol_keys
|
||||||
result
|
result
|
||||||
when -> (arg) { arg.respond_to?(:permitted?) && arg.respond_to?(:to_h) }
|
|
||||||
serialize_indifferent_hash(argument.to_h)
|
|
||||||
else
|
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)
|
ActiveJob.deprecator.warn(<<~MSG)
|
||||||
Primitive serialization of BigDecimal job arguments is deprecated as it may serialize via .to_s using certain queue adapters.
|
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.
|
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.
|
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.
|
This will ensure that during your deployment all replicas are capable of deserializing arguments serialized with BigDecimalSerializer.
|
||||||
MSG
|
MSG
|
||||||
return argument
|
argument
|
||||||
end
|
else
|
||||||
|
|
||||||
Serializers.serialize(argument)
|
Serializers.serialize(argument)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
def deserialize_argument(argument)
|
def deserialize_argument(argument)
|
||||||
case argument
|
case argument
|
||||||
when *PERMITTED_TYPES
|
when nil, true, false, String, Integer, Float
|
||||||
argument
|
argument
|
||||||
when BigDecimal # BigDecimal may have been legacy serialized; Remove in 7.2
|
when BigDecimal # BigDecimal may have been legacy serialized; Remove in 7.2
|
||||||
argument
|
argument
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require "json"
|
||||||
require "bigdecimal"
|
require "bigdecimal"
|
||||||
require "helper"
|
require "helper"
|
||||||
require "active_job/arguments"
|
require "active_job/arguments"
|
||||||
|
@ -23,6 +24,24 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
||||||
end
|
end
|
||||||
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
|
setup do
|
||||||
@person = Person.find("5")
|
@person = Person.find("5")
|
||||||
end
|
end
|
||||||
|
@ -124,6 +143,19 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
||||||
assert_arguments_unchanged MyClassWithPermitted
|
assert_arguments_unchanged MyClassWithPermitted
|
||||||
end
|
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
|
test "serialize a hash" do
|
||||||
symbol_key = { a: 1 }
|
symbol_key = { a: 1 }
|
||||||
string_key = { "a" => 1 }
|
string_key = { "a" => 1 }
|
||||||
|
|
Loading…
Reference in New Issue