Serialize classes and modules with ActiveJob

This commit allows ActiveJob to serialize classes and modules without a custom serializer. This allows for workflows like:

```
class EmailJob < ApplicationJob
  queue_as :default
  def perform(template_class, *arguments)
    template_class.new(*arguments).send!
  end
end

module Email
  class FooTemplate ... end
  class BarTemplate ... end
end

EmailJob.perform_later(Email::FooTemplate, ...)
EmailJob.perform_later(Email::BarTemplate, ...)
```

Currently this is only achieveable through a custom serializer or through constantizing in each instance.
This commit is contained in:
Kevin Deisz 2019-09-09 16:42:16 -04:00
parent 352560308b
commit fbebeabd6d
No known key found for this signature in database
GPG Key ID: D78C2D8FB232C59C
5 changed files with 40 additions and 3 deletions

View File

@ -1,3 +1,7 @@
* Allow `Class` and `Module` instances to be serialized.
*Kevin Deisz*
* Log potential matches in `assert_enqueued_with` and `assert_performed_with`
*Gareth du Plooy*

View File

@ -15,6 +15,7 @@ module ActiveJob
autoload :DateSerializer
autoload :TimeWithZoneSerializer
autoload :TimeSerializer
autoload :ModuleSerializer
mattr_accessor :_additional_serializers
self._additional_serializers = Set.new
@ -58,6 +59,7 @@ module ActiveJob
DateTimeSerializer,
DateSerializer,
TimeWithZoneSerializer,
TimeSerializer
TimeSerializer,
ModuleSerializer
end
end

View File

@ -0,0 +1,20 @@
# frozen_string_literal: true
module ActiveJob
module Serializers
class ModuleSerializer < ObjectSerializer # :nodoc:
def serialize(constant)
super("value" => constant.name)
end
def deserialize(hash)
hash["value"].constantize
end
private
def klass
Module
end
end
end
end

View File

@ -8,6 +8,12 @@ require "jobs/kwargs_job"
require "support/stubs/strong_parameters"
class ArgumentSerializationTest < ActiveSupport::TestCase
module ModuleArgument
class ClassArgument; end
end
class ClassArgument; end
setup do
@person = Person.find("5")
end
@ -18,14 +24,17 @@ class ArgumentSerializationTest < ActiveSupport::TestCase
DateTime.new(2001, 2, 3, 4, 5, 6, "+03:00"),
ActiveSupport::TimeWithZone.new(Time.utc(1999, 12, 31, 23, 59, 59), ActiveSupport::TimeZone["UTC"]),
[ 1, "a" ],
{ "a" => 1 }
{ "a" => 1 },
ModuleArgument,
ModuleArgument::ClassArgument,
ClassArgument
].each do |arg|
test "serializes #{arg.class} - #{arg} verbatim" do
assert_arguments_unchanged arg
end
end
[ Object.new, self, Person.find("5").to_gid ].each do |arg|
[ Object.new, Person.find("5").to_gid ].each do |arg|
test "does not serialize #{arg.class}" do
assert_raises ActiveJob::SerializationError do
ActiveJob::Arguments.serialize [ arg ]

View File

@ -355,6 +355,8 @@ ActiveJob supports the following types of arguments by default:
- `Hash` (Keys should be of `String` or `Symbol` type)
- `ActiveSupport::HashWithIndifferentAccess`
- `Array`
- `Module`
- `Class`
### GlobalID