2012-03-14 55 views
2

模型 「一」如何避免ActiveRecord模型雙重保存?

class One < ActiveRecord::Base 
    before_save :do_stuff 

    private 
    def do_stuff 
     two = Two.find(8) 
     two.field2 = 'Value' 
     two.save! 
    end 
end 

型號 「兩」

class Two < ActiveRecord::Base 
    before_save :do_stuff 

    private 
    def do_stuff 
     one = One.find(7) 
     one.field2 = 'SomeValue' 
     one.save! 
    end 
end 

執行:

two = Two.find(1) 
two.somefield = 'NewVal' 
two.save! 

無限循環將開始。什麼是ruby-on-rails最實用的方式來實現兩個模型,它們必須在before_save回調時互相改變?

+0

你究竟想在這裏實現什麼? – 2012-03-14 14:23:30

+2

即使你有設計上的問題,即使你會解決當前的問題,這也會導致你到下一個問題 – megas 2012-03-14 14:44:37

+0

+1,即使這看起來像設計上的缺陷我已經在這種類型的_cycle中多次發現我的自己回調引用hell_。可以幫助有可能[避免回調adhoc](http://stackoverflow.com/questions/632742/how-can-i-avoid-running-activerecord-callbacks) – fguillen 2012-03-14 14:57:54

回答

2

在希望極少數情況下,您需要這樣做,您可能需要使用attr_accessor禁用before_save過濾器或將其移至after_save塊以避免循環。

例如:

class One < ActiveRecord::Base 
    attr_accessor :not_doing_stuff 
    before_save :do_stuff, 
    :unless => :not_doing_stuff 

private 
    def do_stuff 
    two = Two.find(8) 
    two.field2 = 'Value' 
    two.save! 
    end 
end 

你會禁用觸發它們中的至少一個:

class Two < ActiveRecord::Base 
    before_save :do_stuff 

private 
    def do_stuff 
    one = One.find(7) 
    one.not_doing_stuff = true 
    one.field2 = 'SomeValue' 
    one.save! 
    end 
end 

像這樣的事情總是非常難看,所以儘量避免它,除非你能別想辦法。如果你需要它,確保你已經編寫了足夠的單元測試,以確保它在某些邊緣情況下不會鎖定爲無限循環。

+0

非常聰明..喜歡它! :) – fguillen 2012-03-14 14:59:44

1

不要在before_save中調用save:它會觸發無限循環。返回true或false - 如果你放入before_save成功,返回true,否則返回false。返回false將取消保存和所有其他回調。