猴子修补活跃的工作

时间:2014-12-23 23:51:50

标签: ruby-on-rails monkeypatching rails-activejob

我有一个问题猴子修补ActiveJobs的一部分。我在config / initializers / extensions / arguements.rb

中有以下代码
module ActiveJob
  module Arguments
    TYPE_WHITELIST = [ Date, DateTime, Time, NilClass, Fixnum, Float, String, TrueClass, FalseClass, Bignum ]
  end
end

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

加载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之前没有加载,因此在我的补丁之后加载并覆盖它,虽然我不知道如何修复它。

2 个答案:

答案 0 :(得分:0)

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

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

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

相反,使用GlobalIds按照there所描述的方式对时间类进行monkeypatch,这是序列化任何用于ActiveJob的param的常规方法

基本上你可以这样修补你的课程

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,但这比什么都好?

答案 1 :(得分:-1)

这个怎么样?

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 。遗憾的是,您无法使用细化(read Matz' comment here)

更改常量