【问题标题】:How to organize complex callbacks in Rails?如何在 Rails 中组织复杂的回调?
【发布时间】:2012-07-18 00:59:46
【问题描述】:

我有一个 Rails 应用程序,它经常使用回调。所以我有很多函数在多个模型中被调用:after_create 和 :after_commit。

我想知道我现在的做法是不是最好的。

基本上我有以下场景:

Class Parent < ActiveRecord::Base

has_many :children


after_create :first_function 
after_commit :last_function

    def first_function
        if !self.processed?
            self.children.create(:name => "Richard The Lion Heart")
            self.processed = true
            self.save!
        end
    end

    def last_function
        if self.processed?
            if !self.processing?
                self.process
                                    self.save!
                self.processing = true
                self.save!
            end
        end
    end

end

所以你可以看到整个事情依赖于一些奇怪的双重布尔检查,因为否则每次更新模型时都会调用 second_function 并且它可以由函数本身更新,因此函数会被重复调用。

总的来说,这导致我必须为每个回调引入一个新的布尔检查以触发。它有效,但我不认为它很优雅。我错过了什么?

【问题讨论】:

  • 这可以在 before_save 之前完成吗?

标签: ruby-on-rails callback


【解决方案1】:

您应该能够重写该代码——像这样?当然,您的真实代码可能有一些额外的复杂性——另外:此代码未经测试

Class Parent < ActiveRecord::Base
  has_many :children

  # only called when a new record is created
  after_create :first_function 

  # only called for updates, not new records, should still be inside the current transaction
  after_update :last_function

  private
    def first_function
      self.children.create(:name => "Richard The Lion Heart")
      # don't call save in here, already in a transaction
    end

    def last_function
      self.process
      # don't call save in here, already in a transaction        
    end

    def process
      # doing stuff ....
      self.children[0].update_attribute(:name, "Beowulf")
    end
end    

http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html

总共有 12 个回调,这使您能够为 Active Record 生命周期中的每个状态做出反应和准备。为现有记录调用 Base#save 的顺序类似,只是每个 _create 回调被相应的 _update 回调替换。

用法

p = Parent.new(:foo => "bar")
p.save
p.children[0].name
# => "Richard The Lion Heart"

p.update_attributes(:baz => "fud")
p.children[0].name
# => Beowulf

来自 rails 控制台的 ActiveRecord 回调(使用 awesome_print ap)

> ap ActiveRecord::Callbacks::CALLBACKS
[
  [ 0] :after_initialize,
  [ 1] :after_find,
  [ 2] :after_touch,
  [ 3] :before_validation,
  [ 4] :after_validation,
  [ 5] :before_save,
  [ 6] :around_save,
  [ 7] :after_save,
  [ 8] :before_create,
  [ 9] :around_create,
  [10] :after_create,
  [11] :before_update,
  [12] :around_update,
  [13] :after_update,
  [14] :before_destroy,
  [15] :around_destroy,
  [16] :after_destroy,
  [17] :after_commit,
  [18] :after_rollback
]

【讨论】:

  • 只是为了确保我得到正确 - 你建议使用 :after_update 而不是 :after_commit b/c :after_update 在记录刚刚更新但未保存时被调用,因此它可以在 :after_commit?
  • 我从未使用过after_commit,但after_update 将在保存现有记录期间运行;观察日志文件——更新后将与父保存在同一个数据库事务中;我猜after_commit 将在该事务完成后运行(猜测 - 这就是你必须调用 save 自己的原因) - 使用回调更新答案
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-20
  • 1970-01-01
  • 2013-02-21
  • 2013-02-04
  • 2014-11-05
相关资源
最近更新 更多