【问题标题】:MonkeyPatching ActiveJobsMonkeyPatching ActiveJobs
【发布时间】:2015-02-22 03:31:03
【问题描述】:

我在 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 之前没有加载,因此在我的补丁之后加载并覆盖它,尽管我不知道如何解决这个问题。

【问题讨论】:

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


    【解决方案1】:

    编辑:不要使用,见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
    

    然后,正如 cmets 中所说,您应该扩展此模块:

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

    如果您使用 ruby​​ 2+,更好的方法是使用 Refinements。不幸的是,您不能通过细化来更改常量(read Matz' comment here)

    【讨论】:

    • 所以我不久前才弄清楚这一点,你的答案是部分正确的。您还需要在 ActionMailer::DelieryJob 中扩展它,以便在调用邮件程序时加载它。 module ActionMailer class DeliveryJob &lt; ActiveJob::Base extend ActiveJob::Arguments end end
    • @MattHamada 将您的评论添加到帖子中(或自己发布完整的解决方案)并将其选为最佳答案...
    • @AdrianoTadao 我根据 OP 的评论更新了我的答案。
    【解决方案2】:

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

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

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

    相反,使用 GlobalIds 按照there 的描述对您的时间类进行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 的效果,但这总比没有好是吗?

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-03-05
      • 1970-01-01
      • 2017-10-17
      • 1970-01-01
      • 1970-01-01
      • 2019-05-02
      相关资源
      最近更新 更多