2015-11-19 58 views
1

我有這樣的情況:before_destroy爲模型,破壞相關記錄

class Shop < ActiveRecord::Base 
    has_many :services, dependent: :destroy 
end 

class Service < ActiveRecord::Base 
    has_many :model_weeks, dependent: :destroy 
end 

class ModelWeek < ActiveRecord::Base 
    before_destroy :prevent_destroy, if: :default? 

    private 

    def prevent_destroy 
    false 
    end 
end 

當我試圖摧毀一家店,我得到ActiveRecord::RecordNotDestroyed: Failed to destroy the record,因爲它首先開始銷燬相關的記錄,它就會被阻止在ModelWeek中回調。

只有當我能夠抓住它時,我才能很容易地在銷燬店鋪時取消ModelWeek的默認設置。 Shop模型中的before_destroy在上述引發異常之前未觸發。

那麼,有沒有一種方法可以在Shop模型中捕捉到這一點,或者如果沒有,是否有可能在ModelWeek中「知道」銷燬是由父級觸發的?我調查解析來電,但它沒有提供任何有用的東西,它將是混亂無論如何...

回答

1

一些研究和測試後,這是我想出了:

這是該方法的順序被稱爲(do_before_destroy處於before_destroy回調指定的任何方法):

  • Shop.destroy
  • Service.destroy
  • ModelWeek.destroy
  • ModelWeek.do_before_destroy
  • Service.do_before_destroy
  • Shop.do_before_destroy

所以,我可以處理任何東西的銷燬方法防止兒童(ModelWeek)的破壞父母(店鋪):

# Shop 
def destroy 
    # default is a scope 
    ModelWeek.default.where(service_id: self.services.pluck(:id)).each do |m| 
    m.unset_default 
    end 

    super 
end 

之後,沒有什麼可以防止孩子的破壞,並且鏈條繼續不受阻礙。


UPDATE

甚至有更好,更清潔的解決方案,而無需重寫父的destroy,做任何疑問:

class Shop < ActiveRecord::Base 
    has_many :services, dependent: :destroy, before_remove: :unset_default_week 

    private 

    def unset_default_week(service) 
    service.model_weeks.default.unset_default 
    end 
end 
0

由於鐵軌有從相關的兒童破壞鏈到父母,它真的有道理,對嗎?爲了方便,我們可以覆蓋破壞方法ModelWeek這樣的:

class ModelWeek < ActiveRecord::Base 
    # before_destroy :prevent_destroy, if: :default? 
    def destroy 
    unless default? 
     super 
    end 
    end 
end 
+0

這是如何使它不同?我需要防止銷燬默認的ModelWeek,除非父級(服務)請求銷燬。我怎麼知道在ModelWeek的銷燬方法中? – bosskovic

+0

如果作爲您的描述,我們刪除依賴項,因爲它不工作,它應該工作。在控制器或服務對象中刪除,我想! –

+0

就是這樣,我不想手動去做,我希望它能夠通過rails來管理,並且我發現了其中的兩個解決方案。請看看我發佈的答案。你給了我第一個想法,但最後我跟第二個一起去了,因爲它更乾淨。 – bosskovic

0

我用一個有趣的解決了這個問題hack, 你只需要把before_destroy關聯行 之前,它會運行before_destroy之前刪除協會