2012-07-18 28 views
6

我有一個Rails應用程序,使用回調了很多..這樣我有很多函數調用:after_create和:after_commit在多個模型中。如何在Rails中組織複雜的回調?

我想知道我現在做的方式是否最好。

基本上我有以下情形:

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獲取調用每一個模型被更新時,它可以更新通過函數本身,所以函數被重複調用。

總的來說,它導致我必須引入一個新的布爾檢查來檢查每個回調。它的作品,但我不認爲它是優雅的。我錯過了什麼?

+0

可以這樣做before_save? – cpuguy83 2012-07-18 01:58:44

回答

6

你應該能夠重寫那段代碼 - 就像這樣?當然你的真實代碼可能有一些額外的複雜性 - 也是:這段代碼未經測試

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

這是一個共有十二回調,它給你巨大的力量作出反應,並在活動記錄生命週期的每個狀態做好準備。除了每個_create回調被相應的_update回調代替之外,調用現有記錄的Base#save的順序是相似的。

使用

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 

的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 
] 
+0

只是爲了確保我得到它 - 你建議使用:after_update over:after_commit b/c:當記錄剛更新但未保存時調用after_update,因此它可以在after_commit之前? – Stpn 2012-07-28 15:59:40

+0

我從來沒有使用'after_commit',但'after_update'將在保存現有記錄的過程中運行;觀察日誌文件 - 更新之後將與父保存在相同的數據庫事務中;我猜'after_commit'會在事務完成後運行(猜測 - 這就是爲什麼你必須自己調用save) - 用回調更新答案 – house9 2012-07-29 00:30:05

+0

非常感謝 – Stpn 2012-07-29 01:14:50