यह कैसे निर्धारित किया जाए कि कोई रिकॉर्ड अभी बनाया गया है या बाद में अपडेट किया गया है


95

#New_record? फ़ंक्शन निर्धारित करता है कि क्या कोई रिकॉर्ड सहेजा गया है। लेकिन after_saveहुक में यह हमेशा गलत होता है । क्या यह निर्धारित करने का कोई तरीका है कि रिकॉर्ड एक नया बनाया गया रिकॉर्ड है या अपडेट से पुराना है?

मैं एक और कॉलबैक का उपयोग नहीं करने की उम्मीद कर रहा हूं जैसे before_createकि मॉडल में एक ध्वज सेट करना या डीबी में एक और क्वेरी की आवश्यकता है।

किसी भी सलाह की सराहना की है।

संपादित करें: इन नीड यह निर्धारित करने के लिए after_saveहुक, और मेरी विशेष उपयोग के मामले के लिए, कोई updated_atया updated_onटाइमस्टैम्प


1
हम्म शायद पहले में एक पास हो सकता है_साव? बस ज़ोर से सोच
ट्रिप

जवाबों:


168

मैं after_saveकॉलबैक के लिए इसका उपयोग करना चाह रहा था ।

एक सरल समाधान का उपयोग करना है id_changed?(क्योंकि यह समय पर नहीं बदलेगा update) या भले created_at_changed?ही टाइमस्टैम्प कॉलम मौजूद हों।

अपडेट: जैसा कि @mitsy बताते हैं, अगर कॉलबैक के बाहर इस चेक की जरूरत है तो उपयोग करें id_previously_changed?डॉक्स देखें ।



6
एक after_update और after_create के साथ अंतर करना सबसे अच्छा है। कॉलबैक एक सामान्य विधि साझा कर सकता है जो यह इंगित करने के लिए तर्क बनाता है कि क्या यह एक निर्माण या अद्यतन है।
Matthuhiggins

2
यह बदल गया हो सकता है। कम से कम रेल्स 4 में, after_save कॉलबैक after_create या after_update कॉलबैक के बाद चलता है (देखें guide.rubyonrails.org/active_record_callbacks.html )।
मार्क

3
इनमें से किसी भी क्षेत्र की जाँच करना बाहर काम नहीं करता है after_save
फतुहोकू

3
id_changed?रिकॉर्ड सहेजे जाने के बाद गलत होगा (हुक के बाहर कम से कम)। उस स्थिति में, आप उपयोग कर सकते हैंid_previously_changed?
mltsy

31

कोई रेल यहाँ जादू नहीं है जो मुझे पता है, आपको इसे स्वयं करना होगा। आप एक वर्चुअल विशेषता का उपयोग करके इसे साफ कर सकते हैं ...

आपके मॉडल वर्ग में:

def before_save
  @was_a_new_record = new_record?
  return true
end

def after_save
  if @was_a_new_record
    ...
  end
end

26

फिर भी एक और विकल्प है, जो के लिए करते हैं एक है updated_atटाइमस्टैम्प:

if created_at == updated_at
  # it's a newly created record
end

एक बुरा विचार नहीं है, लेकिन ऐसा लगता है कि यह कुछ स्थितियों में बैकफायर कर सकता है (जरूरी नहीं कि बुलेट प्रूफ)।
ऐश ब्लू

जब माइग्रेशन बनाया जाता है तो निर्भर करता है कि create_at और update_at रिकॉर्ड्स बंद हो सकते हैं। इसके अलावा आप हमेशा किसी को रिकॉर्ड करने का मौका देते हैं जो शुरू में इसे सहेजने के बाद सही रिकॉर्ड करता है जो समय को सिर्फ सिंक से बाहर कर सकता है। यह एक बुरा विचार नहीं है, बस ऐसा लगता है जैसे एक और बुलेट प्रूफ कार्यान्वयन जोड़ा जा सकता है।
ऐश ब्लू

रिकॉर्ड शुरू होने के बाद भी वे लंबे समय तक समान हो सकते हैं। यदि किसी रिकॉर्ड को महीनों तक अपडेट नहीं किया गया है, तो यह ऐसा दिखने वाला है जैसे इसे अभी बनाया गया था ।
19

1
@bschaeffer क्षमा करें, मेरे सवाल था, "इसके लिए संभव है created_atबराबर करने के लिए updated_atएक में after_saveकिसी भी जब वह पहली बार बनाई गई है के अलावा अन्य समय में कॉलबैक?"
कोलीन

1
@ कोलिन: रिकॉर्ड बनाते समय, created_atऔर कॉलबैक updated_atमें बराबर होगा after_save। अन्य सभी स्थितियों में, वे after_saveकॉलबैक में समान नहीं होंगे ।
बी.एस. पुरातत्व

22

एक after_createकॉलबैक है जिसे सहेजे जाने के बाद ही रिकॉर्ड को एक नया रिकॉर्ड कहा जाता हैafter_updateउपयोग के लिए एक कॉलबैक भी है यदि यह एक मौजूदा रिकॉर्ड था जिसे बदल दिया गया और बचाया गया। after_saveकॉलबैक, दोनों ही मामलों में कहा जाता है के बाद या तो है after_createया after_updateकहा जाता है।

उपयोग after_create यदि आपको एक नया रिकॉर्ड सहेजने के बाद एक बार कुछ करने की आवश्यकता है।

अधिक जानकारी यहाँ: http://api.rubyonrails.org/classes/ActiveRecord/Callbacks.html


1
अरे, उत्तर के लिए धन्यवाद, इससे मुझे बहुत मदद मिली। चीयर्स मैन, +10 :)
एडम मैकआर्थर

1
यह वास्तव में सच नहीं हो सकता है। यदि आपकी रचना में एसोसिएशन हैं, तो after_create को BEFORE कहा जाता है, इसलिए एसोसिएशन बनाई जाती हैं, इसलिए यदि आपको यह सुनिश्चित करने की आवश्यकता है कि हर चीज बनाई जाए, तो आपको after_save
Niels Kristian

18

चूंकि ऑब्जेक्ट पहले से ही सहेजा गया है, इसलिए आपको पिछले परिवर्तनों को देखने की आवश्यकता होगी। आईडी केवल एक बनाने के बाद बदलनी चाहिए।

# true if this is a new record
@object.previous_changes[:id].any?

एक उदाहरण चर भी है @new_record_before_save। आप निम्न कार्य करके उस तक पहुँच सकते हैं:

# true if this is a new record
@object.instance_variable_get(:@new_record_before_save)

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


मैं वर्तमान में after_saveरेल 4 के उपयोग से कॉलबैक में हूँ और दोनों में से कोई भी इस नए रिकॉर्ड की पहचान करने के लिए काम नहीं कर रहा है।
MCB

मैं कहूंगा कि @object.previous_changes[:id].any?यह काफी सरल और सुरुचिपूर्ण है। रिकॉर्ड अपडेट होने के बाद यह मेरे लिए काम करता है (मैं इसे कॉल नहीं करता after_save)।
१:05:०५ पर दीकिंगॉफ्टथ जूथ

1
@object.id_previously_changed?थोड़ा कम बदसूरत है।
नोबल

RMC after_save4 पर @MCB आप के changes[:id]बजाय देखना चाहते हैं previous_changes[:id]। यह Rails5.1 में बदल रहा है (हालांकि github.com/rails/rails/pull/25337 में चर्चा देखें )
gmcnaughton

previous_changes.key?(:id)एक बेहतर समझ के लिए।
सेबेस्टियन पाल्मा

2

रेल 5.1+ रास्ता:

user = User.new
user.save!
user.saved_change_to_attribute?(:id) # => true

1

रेल्स 4 के लिए (4.2.11.1 को जांचा गया) के परिणाम changesऔर previous_changesतरीके {}अंदर निर्माण पर खाली हैश हैं after_save। इसलिए इस attribute_changed?तरह के तरीके id_changed?उम्मीद के मुताबिक काम नहीं करेंगे।

लेकिन आप इस ज्ञान का लाभ उठा सकते हैं और - यह जानते हुए कि changesअद्यतन में कम से कम 1 विशेषता होनी चाहिए - अगर changesखाली है तो जांचें । एक बार जब आप पुष्टि कर लेते हैं कि यह खाली है, तो आपको ऑब्जेक्ट निर्माण के दौरान होना चाहिए:

after_save do
  if changes.empty?
    # code appropriate for object creation goes here ...
  end
end

0

मैं विशिष्ट होना पसंद करता हूं यहां तक ​​कि मुझे पता है कि :idसामान्य में नहीं बदलना चाहिए, लेकिन

(byebug) id_change.first.nil?
true

यह बहुत अजीब अप्रत्याशित बग खोजने के बजाय हमेशा विशिष्ट होना सस्ता है।

उसी तरह अगर मैं trueअविश्वसनीय तर्क से झंडे की उम्मीद करता हूं

def foo?(flag)
  flag == true
end

यह अजीब कीड़े पर नहीं बैठने के लिए कई घंटे बचाता है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.