【问题标题】:Run a job after 30 minutes when a specific field of object was set设置对象的特定字段后 30 分钟运行作业
【发布时间】:2018-03-21 13:33:14
【问题描述】:

当将设置名为published_at 的竞赛字段时,我需要运行一项向用户发送电子邮件的作业。所以我有一个Contest 模型和一个运行作业的方法:

class Contest < ApplicationRecord

  after_create :send_contest

  private

  def send_contest
    SendContestJob.set(wait: 30.minutes).perform_later(self)
  end

end

但即使published_at 字段为空白,作业也会运行。验证是否存在的字段不是一个选项,因为published_at 可以稍后设置。那么有什么解决方案在设置字段后如何运行作业?先谢谢了。

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-5 jobs


    【解决方案1】:

    ActiveModel::Dirty 可能在这里有用。有了它,您可以检查哪些字段即将更改/已更改:

    person.name # => "bob"
    person.name = 'robert'
    person.save
    person.previous_changes # => {"name" => ["bob", "robert"]}
    

    比如说,如果published_at_changed? 返回真,你就安排了工作。

    【讨论】:

    • 当我在控制台user.name = 'Name' 中保存它然后检查user.name_changed? 它给了我错误,但是如果我不使用user.save 保存用户,然后检查名称是否被改变了,然后我就明白了。
    • @AlexZakruzhetskyi:阅读其余方法,您一定会找到适合您情况的方法
    • @AlexZakruzhetskyi:实际上,阅读这个答案,其中的代码。
    【解决方案2】:

    您可以使用before_save 而不是使用after_create,它会同时针对新记录和现有记录触发。

    if: 和 unless: 选项允许您指定调用回调需要满足的条件,您可以传递 Proc、Lambda 或要调用的方法的名称。

    class Contest < ApplicationRecord
    
      before_save :send_contest, if: -> { published_at.present? && published_at_changed? }
    
      # or
      before_save :send_contest, if: :publishable?
    
      private
    
      def send_contest
        SendContestJob.set(wait: 30.minutes).perform_later(self)
      end
    
      def publishable?
        published_at.present? && published_at_changed?
      end
    end
    

    按照 Sergio Tulentsev 的建议,您可以使用 ActiveRecord::Dirty 检查列值的更改。请务必仔细阅读文档,因为其中有很多陷阱。

    【讨论】:

    • field_changed? 保存后不再为真。
    • @SergioTulentsev 为真,改为before_save。
    • 但您的答案也使用 AM::Dirty。 field_changed? 来自那里 :)
    • 我知道,我只是想提供一些关于它来自何处的上下文。 @SergioTulentsev
    猜你喜欢
    • 2014-10-16
    • 2023-03-12
    • 2020-03-04
    • 2022-12-18
    • 1970-01-01
    • 2014-08-31
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    相关资源
    最近更新 更多