mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Fix string/gid collision in job arguments
Serialize Global IDs as special objects, distinguishable from Strings
This commit is contained in:
parent
391cfc2054
commit
3f1d04e3bb
2 changed files with 38 additions and 6 deletions
|
@ -35,12 +35,15 @@ module ActiveJob
|
|||
end
|
||||
|
||||
private
|
||||
GLOBALID_KEY = '_aj_globalid'.freeze
|
||||
private_constant :GLOBALID_KEY
|
||||
|
||||
def serialize_argument(argument)
|
||||
case argument
|
||||
when *TYPE_WHITELIST
|
||||
argument
|
||||
when GlobalID::Identification
|
||||
argument.to_global_id.to_s
|
||||
{ GLOBALID_KEY => argument.to_global_id.to_s }
|
||||
when Array
|
||||
argument.map { |arg| serialize_argument(arg) }
|
||||
when Hash
|
||||
|
@ -61,16 +64,37 @@ module ActiveJob
|
|||
when Array
|
||||
argument.map { |arg| deserialize_argument(arg) }
|
||||
when Hash
|
||||
argument.each_with_object({}.with_indifferent_access) do |(key, value), hash|
|
||||
hash[key] = deserialize_argument(value)
|
||||
if serialized_global_id?(argument)
|
||||
deserialize_global_id argument
|
||||
else
|
||||
deserialize_hash argument
|
||||
end
|
||||
else
|
||||
raise ArgumentError, "Can only deserialize primitive arguments: #{argument.inspect}"
|
||||
end
|
||||
end
|
||||
|
||||
def serialized_global_id?(hash)
|
||||
hash.size == 1 and hash.include?(GLOBALID_KEY)
|
||||
end
|
||||
|
||||
def deserialize_global_id(hash)
|
||||
GlobalID::Locator.locate hash[GLOBALID_KEY]
|
||||
end
|
||||
|
||||
def deserialize_hash(serialized_hash)
|
||||
serialized_hash.each_with_object({}.with_indifferent_access) do |(key, value), hash|
|
||||
hash[key] = deserialize_argument(value)
|
||||
end
|
||||
end
|
||||
|
||||
RESERVED_KEYS = [GLOBALID_KEY, GLOBALID_KEY.to_sym]
|
||||
private_constant :RESERVED_KEYS
|
||||
|
||||
def serialize_hash_key(key)
|
||||
case key
|
||||
when *RESERVED_KEYS
|
||||
raise SerializationError.new("Can't serialize a Hash with reserved key #{key.inspect}")
|
||||
when String, Symbol
|
||||
key.to_s
|
||||
else
|
||||
|
|
|
@ -31,12 +31,12 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
|||
end
|
||||
|
||||
test 'should convert records to Global IDs' do
|
||||
assert_arguments_roundtrip [@person], [@person.to_gid.to_s]
|
||||
assert_arguments_roundtrip [@person], ['_aj_globalid' => @person.to_gid.to_s]
|
||||
end
|
||||
|
||||
test 'should dive deep into arrays and hashes' do
|
||||
assert_arguments_roundtrip [3, [@person]], [3, [@person.to_gid.to_s]]
|
||||
assert_arguments_roundtrip [{ 'a' => @person }], [{ 'a' => @person.to_gid.to_s }.with_indifferent_access]
|
||||
assert_arguments_roundtrip [3, [@person]], [3, ['_aj_globalid' => @person.to_gid.to_s]]
|
||||
assert_arguments_roundtrip [{ 'a' => @person }], [{ 'a' => { '_aj_globalid' => @person.to_gid.to_s }}.with_indifferent_access]
|
||||
end
|
||||
|
||||
test 'should stringify symbol hash keys' do
|
||||
|
@ -51,6 +51,14 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
|
|||
assert_raises ActiveJob::SerializationError do
|
||||
ActiveJob::Arguments.serialize [ { :a => [{ 2 => 3 }] } ]
|
||||
end
|
||||
|
||||
assert_raises ActiveJob::SerializationError do
|
||||
ActiveJob::Arguments.serialize [ '_aj_globalid' => 1 ]
|
||||
end
|
||||
|
||||
assert_raises ActiveJob::SerializationError do
|
||||
ActiveJob::Arguments.serialize [ :_aj_globalid => 1 ]
|
||||
end
|
||||
end
|
||||
|
||||
test 'should not allow non-primitive objects' do
|
||||
|
|
Loading…
Reference in a new issue