2015-10-27 5 views
9

मान्य करने के लिए प्रतीत होता है मुझे एक ऐसी स्थिति मिली है जहां ActiveRecord बाल रिकॉर्ड को अनावश्यक रूप से मान्य कर रहा है। लंबाई के लिए अग्रिम में क्षमा करें क्योंकि यह काफी जटिल है।ActiveRecord अपरिवर्तित बाल रिकॉर्ड को अनावश्यक रूप से

इसमें उन संगठनों के माध्यम से शामिल है जिनका पहले उपयोग किया गया था लेकिन किसी भी तरह से नहीं बदला गया था। यह 3.2 से हाल के मास्टर तक होता है। मुझे यकीन नहीं है कि यह एक डिज़ाइन निर्णय है जिसने अप्रत्याशित व्यवहार या किसी प्रकार की बग का नेतृत्व किया है।

मैं वास्तविक कोड से एक टेस्ट केस को कम कर दिया इस प्रकार है:

मॉडल:

class A < ActiveRecord::Base 
    belongs_to :b 
    has_many :cs, :through => :b 
    before_validation { puts "A" } 
end 

class B < ActiveRecord::Base 
    has_many :as 
    has_many :cs 
    before_validation { puts "B" } 
end 

class C < ActiveRecord::Base 
    belongs_to :b 
    before_validation { puts "C" } 
end 

प्रवासन:

class AddABC < ActiveRecord::Migration 
    def change 
    create_table :as do |t| 
     t.references :b 
    end 

    create_table :bs do |t| 
    end 

    create_table :cs do |t| 
     t.references :b 
    end 
    end 
end 

कम परीक्षण का मामला है कि चलाता है यह इस जब रन है एक खाली डेटाबेस पर:

b = B.create! 
c = C.create! 
b.cs << c 
a = A.new 
a.b = b 
a.cs.first 
puts "X" 
a.valid? 

जो उत्पादन देता है:

B 
C 
C 
X 
A 
C 

कौन सा पता चलता है कि एक एक मान्य अपनी सी सत्यापित करता है।

अब इसे ध्यान में रखते हुए मुझे has_many :validate => false विकल्प से अवगत है, और इसका उपयोग करके, समस्या दूर हो जाती है। लेकिन ऐसा लगता है कि यहां से और अधिक चल रहा है - मेरे साथ भालू।

AR docs say:

: मान्य जब जनक वस्तु बचत यदि गलत, इनसे संबंधित वस्तुओं को मान्य नहीं है। डिफ़ॉल्ट रूप से सच है।

लेकिन मुझे लगता है स्पष्ट रूप से इस रूप में इस भ्रामक सभी रिकॉर्ड का मतलब यह नहीं कर सकते हैं। यदि मैं कभी भी एसोसिएशन नहीं प्राप्त करता हूं (उपरोक्त कोड से a.cs.first हटाएं), तो मुझे ऑब्जेक्ट्स मान्य नहीं होंगे, या मुझे यह मिल जाएगा लेकिन इसका कभी भी उपयोग नहीं करें (a.cs के साथ प्रतिस्थापित करें)।

def validate_collection_association(reflection) 
    if association = association_instance_get(reflection.name) 
     if records = associated_records_to_validate_or_save(association, new_record?, reflection.options[:autosave]) 
     records.each_with_index { |record, index| association_valid?(reflection, record, index) } 
     end 
    end 
    end 

यह association_instance_get जो संघ कैश से हासिल करेगा पर सभी सशर्त है: यह इसलिए है क्योंकि यह lib/active_record/autosave_association.rb जो कोड भी शामिल है में validate_collection_association माध्यम से चला जाता है। कोई कैश का मतलब मान्य करने के लिए कोई रिकॉर्ड नहीं है।

मैंने केवल एक बी मॉडल स्थापित करके एक सरल है Imany करने की कोशिश की है, जो ए को संदर्भित करता है, लेकिन फिर मुझे ए से पहले बी बनाने की आवश्यकता होगी, फिर अगर मैं कोशिश करता हूं तो ए एक नया रिकॉर्ड नहीं होगा इसे सहेजने के लिए, और इस कोड समस्या से बचाता है के रूप में शाखा कहा जाता है अब पहले हो जाएगा:

def associated_records_to_validate_or_save(association, new_record, autosave) 
    if new_record 
     association && association.target 
    elsif autosave 
     association.target.find_all(&:changed_for_autosave?) 
    else 
     association.target.find_all(&:new_record?) 
    end 
    end 

केवल वास्तविक विवरण मैं इसे केवल भरी हुई रिकॉर्ड सत्यापित करने के साथ आ सकता है क्योंकि ActiveRecord के इरादे यहाँ केवल बदले गए रिकॉर्ड मान्य करने के लिए है। असल में मैं उम्मीद करता हूं कि यह सत्यापित करने के लिए और केवल तभी सहेजा जा रहा है, और इसलिए बदले गए रिकॉर्ड्स को सहेजने के डिफ़ॉल्ट ऑटोसेव विकल्प को सत्यापन को रोकना चाहिए।

मुझे related ticket और 27aa4dda7d89ce733 प्रतिबद्ध है (अभी तक मुझे लगता है कि किसी भी रिलीज में नहीं) जो एक बदलाव करता है लेकिन मेरे परीक्षण से इस विशिष्ट मुद्दे को ठीक नहीं करता है।हालांकि यह अभिव्यक्ति को नियंत्रित करता है:

!record.persisted? || record.changed? || record.marked_for_destruction? 

और अगर मैं validate_collection_association के अंतरतम पाश को यह शर्त जोड़ तो समस्या ActiveRecord परीक्षण अभी भी मेरे मशीन पर गुजर के साथ, चला जाता है।

यह मेरी परियोजना में एक महत्वपूर्ण प्रदर्शन मुद्दा रहा है क्योंकि प्रश्न में मॉडल केवल व्यवस्थापक में मान्य होना चाहिए, जहां एक वैध सत्यापन में उपयोग किए गए एक अनदेखा क्षेत्र को सहेजने की दुर्लभता के कारण स्वीकार्य था और इस प्रकार मैं यह तय किया गया कि यह अनुक्रमणित करना अधिक अनुक्रमणित होगा (यह केवल एक फ़ील्ड नहीं होगा)। जाहिर है ज्यादातर मामलों में यह अति-सत्यापन बहुत कम गंभीर होगा, और यह केवल एक विशिष्ट मामले में होता है, इसलिए यह एक बग हो सकता है।

इसलिए, मुझे यह पता चल गया कि क्या हो रहा है, मुझे पूरा यकीन नहीं है कि क्या हो रहा है, इसलिए मैंने इसे ActiveRecord टिकट के रूप में दायर नहीं किया है। क्या आपको लगता है कि यह एक बग है? यह इस तरह क्यों काम कर रहा है? वास्तव में वैध विकल्प क्या है? यदि यह एक बग है, तो क्या आप समझा सकते हैं कि कोड इस तरह क्यों काम करता है, और यह क्यों अधिक है? ब्रेक के ऊपर ActiveRecord में मेरा कोड किस मामले में बदल जाएगा?

+0

मुझे यह देखने में दिलचस्पी होगी कि क्या इनवर्क्स_ओफ़ जोड़ना है: एसोसिएशन पर इस व्यवहार को बिल्कुल बदल दिया गया है। टीबीएच मुझे कोई बड़ी उम्मीद नहीं है कि यह होगा, हालांकि। –

+0

मेरे परीक्षण में यह नहीं था। –

उत्तर

3

कारण यह हो रहा है इससे पहले कि आप a.b = b आवंटित क्योंकि ए और सी के बीच के रिश्ते बी

के माध्यम से है, a कोई bs या cs है।

आप a.b = b आवंटित लेकिन आप a.cs फोन नहीं करते हैं, तो a जुड़े cs लोड करने का प्रयास करने का कोई कारण नहीं है। has_many केवल cs सुविधा विधि बनाता है, यह इसे आपके लिए नहीं बुलाता है। यहां केवल a.b_idb.id पर सेट है।

एक बार जब आप फोन a.cs, ab के बाद से b के माध्यम से जुड़े cs वस्तुओं के लिए दिखेगा उपलब्ध है। यह उन वस्तुओं को पायेगा और उन्हें a पर बच्चों के रूप में जोड़ देगा।

मुझे आपकी बात दिखाई देती है, तकनीकी रूप से, cs के लिए इस विशेष स्कीमा में इस विशेष मामले में कुछ भी करने के लिए कुछ नहीं है, लेकिन मैं देख सकता हूं कि क्यों ActiveRecord जांच रहा है। जहां तक ​​यह चिंतित है, इन वस्तुओं, a के बच्चे हैं और बच्चों के रिकॉर्ड तब तक मान्य किए जाते हैं जब तक कि विशेष रूप से validate: false के माध्यम से नहीं कहा जाता।

इस मामले में, ab का एक बच्चा है, इसलिए a को सत्यापित करने के लिए आवश्यक नहीं है।

आम तौर पर, माता-पिता अपने संबंधित बच्चों को सत्यापित करने का कारण बनेंगे। बच्चों को अपने माता-पिता को प्रमाणित करने की आवश्यकता नहीं है।

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