2008-10-19 8 views
27

यदि मैं एक ActiveRecord मॉडल में after_save कॉलबैक जोड़ता हूं, और उस कॉलबैक पर मैं ऑब्जेक्ट को बदलने के लिए update_attribute का उपयोग करता हूं, तो कॉलबैक को फिर से कॉल किया जाता है, और तो एक 'ढेर अतिप्रवाह' होता है (हेहे, प्रतिरोध नहीं कर सका)।कॉलबैक को फिर से ट्रिगर किए बिना उसी ऑब्जेक्ट को संशोधित करने के लिए after_save कॉलबैक का उपयोग करना (रिकर्सन)

क्या इस व्यवहार से बचना संभव है, शायद इसके निष्पादन के दौरान कॉलबैक को अक्षम करना संभव है? या कोई और दृष्टिकोण है?

धन्यवाद!

उत्तर

13

एक वैकल्पिक हल कक्षा में एक चर सेट करने के लिए है, और after_save में अपने मूल्य की जाँच करें।

  1. पहले इसे जांचें। (यदि var)
  2. update_attribute को कॉल करने से पहले इसे 'झूठी' मान पर असाइन करें।
  3. कॉल update_attribute।
  4. इसे 'सत्य' मान पर असाइन करें।
  5. अंत

इस तरह, यह केवल दो बार बचाने के लिए प्रयास करेंगे। यह संभवतः आपके डेटाबेस को दो बार मारा जाएगा, जो वांछित हो सकता है या नहीं।

मैं एक अस्पष्ट भावना में बनाया कुछ है कि है, लेकिन यह एक काफी सरल बस किसी भी आवेदन के बारे में में प्रत्यावर्तन की एक विशिष्ट बिंदु को रोकने के लिए रास्ता है। मैं भी फिर से कोड देखने की सलाह देते हैं के रूप में यह संभव है कि जो कुछ भी आप after_save before_save में किया जाना चाहिए में कर रहे हैं। कई बार यह सच नहीं है, लेकिन वे काफी दुर्लभ हैं।

+0

बहुत बढ़िया! मैंने एक अंतर्निहित दृष्टिकोण की भी खोज की है, लेकिन अब तक ऐसा लगता है कि कोई भी नहीं है, लेकिन यह बहुत अच्छा होगा अगर आप रेल को अस्थायी रूप से उस कॉलबैक को निलंबित करने के लिए कहने के लिए एक विशेष संपत्ति निर्धारित कर सकें ... आपका दृष्टिकोण ऐसा ही है , तो बहुत बहुत धन्यवाद! – Ivan

6

देखें कि update_attribute लागू किया गया है। बजाय भेजने विधि का उपयोग करें:

send(name.to_s + '=', value) 
10

क्या आप इसके बजाय पहले_सेव कॉलबैक का उपयोग कर सकते हैं?

3

आप before_save उपयोग करते हैं, तो आप किसी भी अतिरिक्त पैरामीटर बचाने पूर्ण होने से पहले, जिसका अर्थ है कि आप स्पष्ट रूप बचाने के कॉल करने के लिए नहीं होगा संशोधित कर सकते हैं।

2

धन्यवाद दोस्तों, समस्या यह है कि मैं अन्य वस्तुओं भी (भाई बहन है, तो आप करेंगे) को अद्यतन है ... उस भाग का उल्लेख ...

तो before_save सवाल से बाहर है भूल गया, क्योंकि अगर सहेजने में विफल रहता है अन्य ऑब्जेक्ट्स में सभी संशोधनों को वापस लेना होगा और यह गन्दा हो सकता है :)

3

यह कोड थ्रेडिंग या समवर्ती मुद्दों को हल करने का भी प्रयास नहीं करता है, रेल की तरह उचित है। अगर आपको उस सुविधा की ज़रूरत है, तो सावधान रहें!

असल में, विचार की पुनरावर्ती कॉल के किस स्तर तक गिनती रखने के लिए है "बचाने" आप कर रहे हैं, और केवल after_save अनुमति देते हैं जब आप सर्वोच्च स्तर बाहर निकलने रहे हैं। आप अपवाद हैंडलिंग में भी जोड़ना चाहेंगे।

def before_save 
    @attempted_save_level ||= 0 
    @attempted_save_level += 1 
end 

def after_save 
    if (@attempted_save_level == 1) 
    #fill in logic here 

    save #fires before_save, incrementing save_level to 2, then after_save, which returns without taking action 

    #fill in logic here 

    end 
    @attempted_save_level -= 1 # reset the "prevent infinite recursion" flag 
end 
+0

यह चालाक है, धन्यवाद! – Ivan

7

इसके अलावा आप प्लगइन Without_callbacks पर भी देख सकते हैं। यह एआर आप किसी दिए गए ब्लॉक के लिए कुछ कॉल पीठ को छोड़ देता है कि के लिए एक विधि कहते हैं। उदाहरण:

def your_after_save_func 
    YourModel.without_callbacks(:your_after_save_func) do 
    Your updates/changes 
    end 
end 
+0

उस प्लगइन के बारे में नहीं पता था, यह आसान होगा, धन्यवाद! – Ivan

1

मैं भी इस समस्या थी।मुझे एक विशेषता सहेजने की ज़रूरत है जो ऑब्जेक्ट आईडी पर निर्भर करता है। मैं कॉलबैक के लिए सशर्त मंगलाचरण का उपयोग करके इसे हल ...

Class Foo << ActiveRecord::Base 
    after_save :init_bar_attr, :if => "bar_attr.nil?" # just make sure this is false after the callback runs 

    def init_bar_attr  
     self.bar_attr = "my id is: #{self.id}"  

     # careful now, let's save only if we're sure the triggering condition will fail  
     self.save if bar_attr 
    end 
10

मैं इस सवाल का जवाब नहीं देखा था, इसलिए मैंने सोचा कि मैं इसे जोड़ना होगा मामले में यह इस विषय पर खोज कर किसी को भी मदद करता है। (स्कॉट डी के बिना_callbacks सुझाव करीब है।)

ActiveRecord इस स्थिति के लिए update_without_callbacks प्रदान करता है, लेकिन यह एक निजी विधि है। वैसे भी इसे प्राप्त करने के लिए भेजें का उपयोग करें। जिस वस्तु को आप सहेज रहे हैं उसके लिए कॉलबैक के अंदर होना बिल्कुल इसका कारण है।

इसके अलावा कोई और तो यहाँ थ्रेड कि यह बहुत अच्छी तरह से शामिल किया गया है: How can I avoid running ActiveRecord callbacks?

1

कभी कभी यह क्योंकि मॉडल में attr_accessible निर्दिष्ट नहीं की है। जब update_attribute गुणों को संपादित करना चाहता है, तो पता चलता है कि वे पहुंच योग्य नहीं हैं और इसके बजाय नई ऑब्जेक्ट्स बनाते हैं। नई ऑब्जेक्ट्स को सहेजने पर, यह एक अनदेखी पाश में जाएगा।

0

मैं पाठ के एक ब्लॉक में पथ नाम gsub की जरूरत थी जब अपने रिकॉर्ड एक अलग संदर्भ में कॉपी किया गया था:

attr_accessor :original_public_path 
after_save :replace_public_path, :if => :original_public_path 

private 

def replace_public_path 
    self.overview = overview.gsub(original_public_path, public_path) 
    self.original_public_path = nil 

    save 
end 

प्रत्यावर्तन को रोकने के लिए प्रमुख विशेषता से मान देना था और फिर विशेषता को शून्य पर सेट करें ताकि :if स्थिति बाद की बचत पर पूरा नहीं हो पाई।

2

चाल सिर्फ #update_column उपयोग करने के लिए है:

  • सत्यापन को छोड़ दिया जाता है।
  • कॉलबैक छोड़ दिए गए हैं।
  • अपडेटेड_एट/अपडेटेड_ऑन अपडेट नहीं किए गए हैं।

इसके अतिरिक्त, यह बस डीबी को एक त्वरित अद्यतन क्वेरी जारी करता है।

http://apidock.com/rails/ActiveRecord/Persistence/update_columns

0

आप इस प्रकार if के सहयोग से after_save उपयोग कर सकते हैं:

after_save :after_save_callback, if: Proc.new { 
               //your logic when to call the callback 
               } 

या

after_save :after_save_callback, if: :call_if_condition 

def call_if_condition 
    //condition for when to call the :after_save_callback method 
end 

call_if_condition एक विधि है। इस विधि में after_save_callback पर कॉल करने के लिए परिदृश्य को परिभाषित करें

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