2012-01-25 5 views
19

मैं दो वर्गों है:रेल: before_destroy कॉलबैक निष्क्रिय करने के लिए कैसे जब यह माता पिता की वजह से नष्ट किया जा रहा है को नष्ट कर दिया जा रहा है (: निर्भर =>: नष्ट)

belongs_to :parent 
:

बच्चे के साथ माता पिता और बच्चे

और

जनक

has_many :children, :dependent => :destroy 
समस्या

है कि मुझे लगता है कि टी जाँच करना चाहते हैं यहां हमेशा कम से कम एक बच्चा मौजूद होता है, इसलिए मेरे पास बच्चे में पहले से ही डीड्रॉय विधि है जो नष्ट हो जाती है अगर यह अपने माता-पिता से संबंधित एकमात्र बच्चा है।

और, यदि मैं माता-पिता को नष्ट करना चाहता हूं, तो यह प्रत्येक बच्चे पर पहले_डस्ट्राय कॉलबैक को कॉल करेगा, लेकिन जब कोई बच्चा होता है, तो यह नष्ट हो जाएगा, इसलिए माता-पिता कभी नष्ट नहीं होंगे।

मैं बच्चे को पहले से ही कॉलबैक कॉल करने के लिए कैसे कह सकता हूं अगर इसे अपने माता-पिता के कारण नष्ट नहीं किया जा रहा है?

धन्यवाद!

+0

क्या 'माता-पिता -> बाल' संबंध का नाम 'बच्चों 'नहीं होना चाहिए? मुझे पूरा यकीन है कि रेल समझ जाएंगे कि आप वैसे भी 'चाइल्ड' मॉडल को इंगित कर रहे हैं। – Frost

+0

हाहा हाँ ... ठीक है, वे वास्तविक नाम नहीं हैं, इसलिए इससे कोई फर्क नहीं पड़ता :) मेरी मुट्ठी भाषा अंग्रेजी नहीं है, और मैं बच्चे के बहुवचन को भूल गया है –

उत्तर

10
has_many :childs, :dependent => :delete_all 

यह सभी बच्चों किसी भी हुक चलने के बिना को नष्ट करेगा।

आपको कम से प्रलेखन पा सकते हैं: http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#method-i-has_many

+2

धन्यवाद! जो काम करता था, लेकिन मैं जानना चाहता हूं कि क्या सभी बच्चों को यह बताने का कोई तरीका है कि उन्हें नष्ट किया जा रहा है: निर्भर =>: कॉलबैक को नष्ट करें। चूंकि मेरे चाइल्ड क्लास पर पहले से ही डीड्रॉइड कॉलबैक हैं, इसलिए मैं –

+1

जोस को कॉल करना चाहता हूं, मेरा सुझाव है कि आप अपने पहले_डेस्ट्राय कॉलबैक को सार्थक नामों के साथ तरीकों से बाहर खींचें। एक नया first_destroy कॉलबैक जोड़ें जो कुछ ऐसा करता है: 'children.all {| child | child.do_something; child.do_something_else} '। दूसरे शब्दों में, माता-पिता माता-पिता को नष्ट होने से पहले माता-पिता को अपने बच्चों पर मैन्युअल रूप से कॉल कर सकते हैं (और बच्चों को ': निर्भर =>: delete_all' द्वारा हटाया जाता है) –

1

वहाँ शायद एक कम hacky फैशन में यह पूरा करने के लिए एक रास्ता है, लेकिन यहां एक (अपरीक्षित!) विचार है: एक attr_accessor :destroyed_by_parentChild और संपादित बच्चे की before_destroy फ़िल्टर जोड़ें नष्ट जब यह true है अनुमति देने के लिए।

अपने सभी बच्चों पर कि दोहराता Parent करने के लिए एक before_destroy फ़िल्टर जोड़ें:

private 

# custom before_destroy 
def set_destroyed_by_parent 
    self.children.each {|child| child.destroyed_by_parent = true } 
end 

बशर्ते कि :dependent => :destroy से शुरू हो रहा जनक वस्तु के instanced बच्चों पर निष्पादित किया जाता है को नष्ट, यह काम कर सकता था। अगर यह अलग-अलग बच्चों को तुरंत चालू करता है, तो यह काम नहीं करेगा।

+2

दुर्भाग्यवश बच्चों के पहले_डेस्ट्राय कॉलबैक को माता-पिता के सामने बुलाया जाएगा , इसलिए माता-पिता को नरसंहार करने से पहले माता-पिता को आवृत्ति चर सेट करने का मौका नहीं मिलेगा। – RobHeaton

4

अगर आप before_destroy पद्धति पर सच करने के लिए आगे जोड़ते सेट कार्प के जवाब से ऊपर काम करेंगे। इस प्रयास करें:

बाल:

belongs_to :parent 
before_destroy :prevent_destroy 
attr_accessor :destroyed_by_parent 

... 

private 

def prevent_destroy 
    if !destroyed_by_parent 
    self.errors[:base] << "You may not delete this child." 
    return false 
    end 
end 

जनक:

has_many :children, :dependent => :destroy 
before_destroy :set_destroyed_by_parent, prepend: true 

... 

private 

def set_destroyed_by_parent 
    children.each{ |child| child.destroyed_by_parent = true } 
end 

क्योंकि हम मानसिक उन्माद का उपयोग कर रहे हैं, और dependent: delete_all कड़ी मेहनत से हटाने के बजाय उन्हें नरम हटाना होगा यह करने के लिए किया था। मेरा आंत मुझे बताता है कि ऐसा करने का एक बेहतर तरीका है, लेकिन यह स्पष्ट नहीं है, और यह काम पूरा हो जाता है।

1

स्वीकृत उत्तर मूल समस्या को हल नहीं करता है।जोस 2 बातें करना चाहता था:

1) यह सुनिश्चित करने के जनक हमेशा की तरह ही कम से कम एक बच्चे

और

2) जब जनक

आप हटा दी जाती है सभी बच्चों को हटाने के लिए सक्षम होने के लिए किसी बच्चे को हटाने से रोकने के लिए before_destroy कॉलबैक की आवश्यकता नहीं है।

मैंने detailed blog post describing the solution लिखा, लेकिन मैं यहां मूल बातें भी शामिल करूंगा।

समाधान में विभिन्न तत्व शामिल हैं: अभिभावक मॉडल में उपस्थिति सत्यापन और नेस्टेड विशेषताओं का उपयोग, और यह सुनिश्चित करना कि बच्चे को हटाए जाने वाली विधि बच्चे पर .destroy पर कॉल नहीं करती है, लेकिन बच्चे को हटा दिया जाता है नेस्टेड विशेषताओं के माध्यम से अभिभावक मॉडल।

जनक मॉडल में:

attr_accessible :children_attributes 

has_many :children, dependent: :destroy 
accepts_nested_attributes_for :children, allow_destroy: true 
validates :children, presence: true 

बच्चे मॉडल में:

belongs_to :parent 

इसके बाद, बच्चों, हटाए जाने के लिए पिछले एक को छोड़कर अनुमति देने के लिए सबसे आसान तरीका है, है नेस्ट का उपयोग करने के लिए फॉर्म, जैसा कि Railscasts #196 में शामिल है। असल में, आपके पास माता-पिता और बच्चों दोनों के लिए फ़ील्ड के साथ एक फॉर्म होगा। स्थान के साथ-साथ बच्चों के विलोपन सहित बच्चों के लिए कोई भी अपडेट, माता-पिता नियंत्रक में update कार्रवाई द्वारा संसाधित किया जाएगा।

जिस तरह से आप नेस्टेड रूपों के माध्यम से बच्चे को हटाते हैं, वह _destroy नामक कुंजी में गुजरकर एक वास्तविक मूल्य का मूल्यांकन करता है। allow_destroy: true विकल्प जिसे हम अभिभावक मॉडल में सेट करते हैं वह यह है कि यह क्या अनुमति देता है। Active Record Nested Attributes के लिए दस्तावेज़ इस को शामिल किया गया है, लेकिन यहाँ एक त्वरित उदाहरण से पता चलता है कि कैसे आप एक बच्चे जिसका id के बराबर होती है 2 इसके जनक से हटाना होगा है:

parent.children_attributes = { id: '2', _destroy: '1' } 
parent.save 

ध्यान दें कि आप जनक नियंत्रक में इस खुद कर की जरूरत नहीं है यदि आप रेलस्टास्ट # 1 9 6 में नेस्टेड रूपों का उपयोग कर रहे हैं। रेल आपके लिए इसका ख्याल रखती है।

अभिभावक मॉडल में उपस्थिति सत्यापन के साथ, रेल स्वचालित रूप से अंतिम बच्चे को हटाए जाने से रोक देगा।

मुझे लगता है कि उस समय जोस ने अपना प्रश्न पोस्ट किया था, उपस्थिति सत्यापन उस तरीके से काम नहीं कर रहा था जिस तरह से यह माना जाता था। यह जुलाई 2012 तक इस pull request के साथ तय नहीं किया गया था, लेकिन यह लगभग 2 साल पहले था। 12 दिन पहले अपने पुराने समाधान को डीबॉर्टज़ को देखते हुए मुझे एहसास हुआ कि इस मुद्दे के बारे में अभी भी भ्रम है, इसलिए मैं सही समाधान पोस्ट करना सुनिश्चित करना चाहता था।

एक वैकल्पिक समाधान है कि नेस्टेड रूपों का उपयोग नहीं करता है, अपने ब्लॉग पोस्ट को देखने के लिए: जब सीधे पर destroy बुला

class Parent < AR::Base 
    has_many :children, dependent: :destroy 
end 

class Child < AR::Base 
    belongs_to :parent 

    before_destroy :check_destroy_allowed, unless: :destroyed_by_association 

    private 

    def check_destroy_allowed 
    # some condition that returns true or falls 
    end 
end 

इस तरह,: http://www.moncefbelyamani.com/rails-prevent-the-destruction-of-child-object-when-parent-requires-its-presence/

+0

हाय मॉन्सेफ, आपके उत्तर के लिए धन्यवाद। तो बेसिक रूप से, मैं नेस्टेड विशेषताओं और remove_child (id) जैसी विधि का उपयोग करके इस समस्या को हल करने में सक्षम हूं जिसमें मैं _destroy सेट को सही (या 1) के साथ bab_attributes अद्यतन करता हूं, और इसे मूल child.destroy विधि के रूप में उपयोग करता हूं , सही? मुझे लगता है कि यह सही समाधान है, लेकिन सबसे अच्छा परिदृश्य होगा जहां यह child.destroy –

+0

का डिफ़ॉल्ट व्यवहार है, यह सही है, लेकिन यदि आपके पास अपने ऐप में यूआईएस है जो नेटस्ड फॉर्मों जैसे रेलसकास्ट # 1 9 6 में है, तो आपके पास नहीं है बच्चे को हटाने के लिए एक अलग विधि बनाने के लिए। रेल इसे माता-पिता में 'अपडेट' कार्रवाई के माध्यम से स्वचालित रूप से करता है। यह कैसे काम करता है यह देखने के लिए Railscasts # 1 9 6 देखें। – monfresh

3

रेल 4 में आप निम्न कर सकते एक बच्चा check_destroy_allowed कॉलबैक चलाएगा, लेकिन जब आप माता-पिता पर destroy पर कॉल करेंगे, तो यह नहीं होगा।

संबंधित मुद्दे