2012-01-17 52 views
4

我想在從has_many關聯中刪除對象之前運行一些代碼。爲什麼在這個has_many關聯中沒有「before_remove」射擊?

我認爲我可以用before_remove回調做到這一點,但由於某種原因,這不是解僱,我不明白爲什麼。

class Person < ActiveRecord::Base 
    has_many :limbs, before_remove: :print_message 

    def print_message 
    puts 'removing a limb' 
    end 
end 

class Limb < ActiveRecord::Base 
    belongs_to :person 
end 

儘管此代碼應該打印肢體的破壞過程「消除肢體」但事實並非如此。

p = Person.create; 
l = Limb.create person: p; 
p.limbs.first.destroy 
# SQL (2.1ms) DELETE FROM "limbs" WHERE "limbs"."id" = ? [["id", 5]] 
# => #<Limb id: 5, person_id: 3, created_at: "2012-01-17 11:28:01", updated_at: "2012-01-17 11:28:01"> 

爲什麼這個destroy行動不會導致print_message方法來運行?

編輯 - 是否before_remove回調存在?

許多人詢問這個回調是否存在。雖然我發現很少有人再引用它,它是記錄在Rails文檔中:

http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#label-Association+callbacks

這是一個關聯回調雖然而非根ActiveRecord的回調

編輯2 - 爲什麼不在肢體上使用before_destroy

有人問爲什麼我沒有在肢體上使用before_destroy回調。原因是我希望人們檢查是否有最少數量的肢體,並且最後一個從未被破壞。這是原始問題: How do you ensure that has_many always "has a minimum"?

+0

沒有before_remove。至少我不知道它和文檔http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html似乎證實了我的看法。 – lucapette 2012-01-17 11:41:27

+0

@lucapette它與'ActiveRecord :: Associations :: ClassMethods'有關,而不是'ActiveRecord :: Callbacks'。 – shime 2012-01-17 12:03:20

+0

@shime很高興知道。我沒有遇到它。總是有一些東西要學習;) – lucapette 2012-01-17 14:23:18

回答

13

before_remove存在回調在Associations callbacks一個選項。它與before_destroy不一樣,它是ActiveRecord callback

這是你如何使用它:

class Person < ActiveRecord::Base 
    has_many :limbs, :before_remove => :print_message 

    def print_message(limb) 
    # limb variable references to a Limb instance you're removing 
    # (do some action here) 
    # ... 
    end 
end 

class Limb < ActiveRecord::Base 
    belongs_to :person 
end 

你還調用remove方法不正確。

p = Person.create 
l = Limb.create(:person => p) 
p.limbs.first.destroy 

在這裏你打電話給Limb實例,這就是爲什麼沒有觸發。 叫它你創建的關聯關係:

p = Person.create 
l = Limb.create(:person => p) 
p.limbs.destroy(l) 

編輯

爲維護關聯對象的最低,你可以做這樣的事情:

class Person < ActiveRecord::Base 
    has_many :limbs, :before_remove => :preserve_mimimum 

    def preserve_minimum(limb) 
    raise "Minimum must be preserved" if limbs.count == 1 
    end 
end 

class Limb < ActiveRecord::Base 
    belongs_to :person 
end 

然而,這不會被觸發所以你必須這樣做p.limbs.each {|l| p.limbs.destroy(l)}

爲什麼它不會被destroy_all觸發?

正因爲如此:

def destroy_all(conditions = nil) 
    find(:all, :conditions => conditions).each { |object| object.destroy } 
end 

它遍歷關聯的每個元素並執行對象上,而不是在關聯銷燬行動,這就是原因。

+0

嗨,ime,該方法的目的是爲了保護肢體不被銷燬,但是'destroy'被調用,所以可能這種方法對我來說無論如何不適用。也就是說,我實際上無法使用你的方法來工作 - 你確定你的代碼確實有效嗎? – 2012-01-17 12:53:53

+0

它的工作原理。我編輯了我的帖子以支持「保留最低限度」。 – shime 2012-01-17 13:19:23

+0

謝謝你。我確實得到它的工作,你的例子幫助顯示它不會不幸地解決我需要處理的問題。這就是說,我不清楚這是什麼時候會有用 - 即使是'p.limbs.first.destroy'也不會觸發回調 – 2012-01-17 14:25:24

0

before_remove替換爲before_destroy

編輯 - 處理四肢

class Limb < ActiveRecord::Base 
    belongs_to :creature 
    before_destroy :count_limbs 

    def count_limbs 
    return false if self.creature.limbs.length <= self.creature.min_limbs 
    end 
end 

返回假的意志,我相信,被破壞阻止它的最小數量。雖然我可能是錯的

+0

感謝您的回答 - 我已更新問題,但要顯示它確實存在以及爲什麼需要它。 – 2012-01-17 11:59:59

+0

是否存在'before_remove','before_destroy'應該解決這個問題。是否有一個具體的原因,你正在尋找使用別的東西?我現在正在閱讀你的鏈接。 – 2012-01-17 12:03:39

+0

這種替換拋出'ArgumentError:未知的鍵:(s):before_destroy' – shime 2012-01-17 12:06:55

0

我不能說我曾經使用過before_remove回調,並且不確定它是否存在。

的前銷燬回調應該在肢體模型相反,而應該是這樣的:

class Limb < ActiveRecord::Base 
    belongs_to :person 
    before_destroy :print_message 
    def print_message 
    puts 'removing a limb' 
    end 
end 
+0

before_destroy回調可以在肢體上使用,但不能解決我的問題,那就是我希望人員在肢體太少時不允許肢體被摧毀。我更新了這個問題,以引用文檔before_remove – 2012-01-17 11:59:32

相關問題