在Rails中内联`after_commit`回调

时间:2017-01-04 19:43:17

标签: ruby-on-rails

我有一个sidekiq作业,需要在提交后运行以避免a common race condition

class User < ActiveRecord::Base
  ...
  after_commit do |user|
    if @enqueue_some_job
      SomeJob.new(user).enqueue
      @enqueue_some_job = nil
    end
  end

  def verify
    @enqueue_some_job = ...
    ...
    save!
  end
end

代码有点难看。我更愿意以某种方式将回调内联包装成这样:

class User < ActiveRecord::Base
  def verify
    if ...
      run_after_commit do |user|
        SomeJob.new(user).enqueue
      end
    end
    ...
    save!
  end
end

Rails中是否存在任何内容以支持这样的语法(不依赖于设置临时实例变量)?或者是否存在任何扩展Rails的库以添加这样的语法?

3 个答案:

答案 0 :(得分:1)

使用关注点找到解决方案。片段得到了足够的重用,它可能是抽象实例变量并形成可重用模式的更好选择。它不会处理返回(不确定哪些是通过#include <stdio.h> #include <string.h> #include <ctype.h> void rek(char array[], int d) { int counter=0; if(d==0) { printf("%s \n",array); printf("%d \n",counter); } else { if((array[d]>='A' && array[d]<='Z')&&(array[d-1]>='A' && array[d-1]<='Z')) { array[d]=array[d]+32; array[d-1]=array[d-1]+32; counter++; rek(array,d-2); } if((array[d]>='a' && array[d]<='z')&&(array[d-1]>='a' && array[d-1]<='z')) { array[d]=array[d]-32; array[d-1]=array[d-1]-32; counter++; rek(array,d-2); } } } int main() { char array[100]; int d; gets(array); d=strlen(array); rek(array,d); return 0; } 支持的,因为没有事务可以回滚。

应用/模型/关切/ callbackable.rb

after_commit

应用/模型/ user.rb

module Callbackable
  extend ActiveSupport::Concern

  included do

    after_commit do |resource|
      if @_execute_after_commit
        @_execute_after_commit.each do |callback|
          callback.call(resource)
        end
        @_execute_after_commit = nil
      end
    end
  end

  def execute_after_commit(&callback)
    if callback
      @_execute_after_commit ||= []
      @_execute_after_commit << callback
    end
  end

end

答案 1 :(得分:0)

在声明回调时,您可以使用方法名称而不是块:

class User < ActiveRecord::Base
  after_commit :do_something!

  def do_something!
  end
end

要在回调中设置条件,您可以使用ifunless选项。请注意,这些只是哈希选项 - 而不是关键字。

您可以使用方法名称或lambda:

class User < ActiveRecord::Base
  after_commit :do_something!, if: -> { self.some_value > 2 }
  after_commit :do_something!, unless: :something?

  def do_something!
  end

  def something?
    true || false
  end
end

答案 2 :(得分:-1)

假设您需要在创建后验证用户。

after_commit :run_sidekiq_job, on: :create
after_commit :run_sidekiq_job, on: [:create, :update] // if you want on update as well.

这将确保您的作业仅在提交db。

之后运行

然后定义必须执行的工作。

def run_sidekiq_job
  ---------------
  ---------------
end

希望它可以帮助你:)