2010-01-12 27 views
2

我有一個模型,有很多孩子。我設置/這樣除去孩子:爲什麼ActiveRecord has_many使用delete_all而不是destroy_all?

mymodel.children_ids = [1,2,3] 
mymodel.save #add the children 
mymodel.children_ids = [1] 
mymodel.save #remove children 2,3 

這只是正常的,但我才意識到,沒有任何回調(即after_destroy)都沒有被稱爲對孩子的模型。

經過一番挖掘,結果發現delete_all函數正在執行中,而不是destroy_all。正如文檔正確指出的那樣,delete_all函數不會觸發回調,所以無論如何改變這種行爲?

謝謝。

回答

1

對於那些有興趣的人,我添加了以下monkeypatch來強制has_many執行destroy_all而不是delete_all。可能有更好的方法,所以我願意接受建議。

module ActiveRecord 
    module Associations 
    class HasManyThroughAssociation < HasManyAssociation  
     def delete_records(records) 
     klass = @reflection.through_reflection.klass 
     records.each do |associate| 
      klass.destroy_all(construct_join_attributes(associate)) #force auditing by using destroy_all rather than delete all 
     end 
     end 
    end 
    end 
end 
+0

這個解決方案在Rails 3.1.1中還能工作嗎?這不是我的工作,得到錯誤數量的參數(1爲2)' – amree

+0

我不確定...我計劃在幾個月內將我的應用升級到Rails 3.1。我想那時我必須弄清楚這一點。 – gmoniey

1

delete_all正在執行......只是因爲?這就是Rails核心團隊認爲在這種情況下應該被調用的原因。但是,您可以明確地在模型的子項上調用destroy_all方法,但不使用該類型的查詢。它看起來像是直接設置子標識,不使用任何build()destroy()方法。

是的,你可以覆蓋它的功能。你可以修補它並將其放入/vendor,改爲使用destroy_all重寫相同的代碼塊。然後使用send命令來替換您自己的基本ActiveRecord功能。

+0

我想我可以只猴子修補一段代碼處理這個。 任何想法在哪裏生活? – gmoniey

1

喜歡的東西:

mymodel.children.find([2,3]).each {|c| c.destroy } 

將做的工作。這不完全是你想要的,但我希望它有幫助。

+0

我想我可以重寫模型類中的children_ids =函數,並在那裏處理它......但我希望能有一種更乾淨/乾燥的方式。 – gmoniey

1

我有類似的回調問題。使用alias_method_chain解決它來覆蓋默認設置器。在alias_method_chain

def product_categories_with_destroy=(product_categories) 
    unless new_record? 
     (self.product_categories - product_categories).each(&:destroy) 
    end 

    self.product_categories_without_destroy = product_categories 
    end 
    alias_method_chain :product_categories=, :destroy 

更多細節:

http://yehudakatz.com/2009/03/06/alias_method_chain-in-models/

相關問題