4

我在修补 ActiveJobs 的部分时遇到问题。我在 config/initializers/extensions/arguements.rb 中有以下代码

module ActiveJob
  module Arguments
    TYPE_WHITELIST = [ Date, DateTime, Time, NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
  end
end

基本上,我正在尝试添加对日期/时间对象的基本支持,以便在 ActionMailer#deliver_later 创建的 ActiveJob 中使用

加载 rails 应用程序后,我可以看到我的白名单已加载,但是当我在邮件程序上调用 Deliver_later 方法时,原始白名单会覆盖我的补丁。

#List is correct when app loads
2.1.2 :002 > ActiveJob::Arguments::TYPE_WHITELIST
 => [Date, DateTime, Time, NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum] 

#List is overridden by default list in ActiveJobs after running #deliver_later
2.1.2 :005 > ActiveJob::Arguments::TYPE_WHITELIST
 => [NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum] 

如何使修改后的白名单保持不变?我很确定错误源于原始的 ActiveJob::Arguments 在调用 Deliver_later 之前没有加载,因此在我的补丁之后加载并覆盖它,尽管我不知道如何解决这个问题。

4

2 回答 2

3

@Pak 给出的解决方案可能很危险!

TL;DR:它与嵌套哈希中的时间对象中断,因为在反序列化期间,它们将作为字符串返回

因此,在生产中,您实际上希望能够将时间序列化为字符串并将“时间字符串”反序列化为时间对象。如果您只是将 Time 添加到类型白名单中,序列化和反序列化在常规参数中可能工作得很好,但是如果您在散列参数中发送您的时间对象,它将中断,并且几乎不可能编写失败的测试。

相反,使用GlobalIds 对你的时间类进行monkeypatch,这是序列化任何参数以与 ActiveJob 一起使用的常规方法

基本上你可以通过这种方式修补你的课程

class Time
  include GlobalID::Identification

  alias_method :id, :to_i
  def self.find(seconds_since_epoch)
    Time.at(seconds_since_epoch.to_i)
  end
end

class ActiveSupport::TimeWithZone
  include GlobalID::Identification

  alias_method :id, :to_i
  def self.find(seconds_since_epoch)
    Time.zone.at(seconds_since_epoch.to_i)
  end
end

因此,您可以正确序列化/反序列化您的参数

arguments = [1, { start: Time.now, end: 1.day.ago }]
serialized_arguments = ActiveJob::Arguments.serialize(arguments)
# => [1,
# {"start"=>{"_aj_globalid"=>"gid://my-job-glasses/Time/1528381306"},
#  "end"=>{"_aj_globalid"=>"gid://my-job-glasses/Time/1528294906"},
#  "_aj_symbol_keys"=>["start", "end"]}]
deserialized_arguments = ActiveJob::Arguments.deserialize(serialized_arguments)
# => [1, {:start=>"2018-06-07T16:21:46.000+02:00", :end=>"2018-06-06T16:21:46.000+02:00"}]

deserialized_arguments.last[:start].class # => Time

请注意,这具有转换AS:TWZ为普通旧的效果,Time但这总比没有好是吗?

于 2018-06-07T14:28:46.503 回答
0

编辑:不要使用,请参阅https://stackoverflow.com/a/50743819/3293310


那这个呢 ?

module ActiveJob
  module Arguments 
    remove_const(:TYPE_WHITELIST)
    TYPE_WHITELIST = [ Date, DateTime, Time, NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
  end
end

然后,如评论中所述,您应该扩展此模块:

module ActionMailer 
  class DeliveryJob < ActiveJob::Base 
    extend ActiveJob::Arguments 
  end
end

如果您使用 ruby​​ 2+,更好的方法是使用Refinements。不幸的是,您不能通过改进来更改常量(在此处阅读 Matz 的评论)

于 2015-01-26T11:06:07.850 回答