रेल्स का उपयोग क्यों कर रहा है default_scope के खिलाफ अक्सर सलाह देते हैं?


126

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

तो: क्यों रेल के default_scopeखिलाफ की सिफारिश की है?

जवाबों:


192

समस्या 1

आइए मूल उदाहरण पर विचार करें:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
end

डिफ़ॉल्ट बनाने की प्रेरणा published: true, यह सुनिश्चित करने के लिए हो सकती है कि अप्रकाशित (निजी) पोस्ट दिखाने के लिए आपको खोज करनी पड़े। अब तक सब ठीक है।

2.1.1 :001 > Post.all
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't'

वैसे यह बहुत ज्यादा है जो हम उम्मीद करते हैं। अब कोशिश करते हैं:

2.1.1 :004 > Post.new
 => #<Post id: nil, title: nil, published: true, created_at: nil, updated_at: nil>

और वहाँ हम डिफ़ॉल्ट समस्या के साथ पहली बड़ी समस्या है:

=> default_scope आपके मॉडल इनिशियलाइज़ेशन को प्रभावित करेगा

इस तरह के एक मॉडल के नए बनाए गए उदाहरण में, default_scopeपरिलक्षित होगा। इसलिए जब आप संयोग से अप्रकाशित पदों को सूचीबद्ध नहीं करना चाहते हैं, तो आप अब डिफ़ॉल्ट रूप से प्रकाशित कर रहे हैं।

समस्या २

एक अधिक विस्तृत उदाहरण पर विचार करें:

class Post < ActiveRecord::Base
  default_scope { where(published: true) }
  belongs_to :user
end 

class User < ActiveRecord::Base
  has_many :posts
end

आओ हम पहले उपयोगकर्ताओं को पोस्ट करें:

2.1.1 :001 > User.first.posts
  Post Load (0.3ms)  SELECT "posts".* FROM "posts"  WHERE "posts"."published" = 't' AND "posts"."user_id" = ?  [["user_id", 1]]

यह अपेक्षित लगता है (उपयोगकर्ता_आईडी के बारे में भाग को देखने के लिए दाईं ओर स्क्रॉल करने के लिए सुनिश्चित करें)।

अब हम सभी पदों की सूची प्राप्त करना चाहते हैं - अप्रकाशित शामिल - उपयोगकर्ता के दृश्य में लॉग के लिए कहें। आपको एहसास होगा कि आपको 'ओवरराइट' या 'पूर्ववत' करना है default_scope। एक त्वरित गूगल के बाद, आप के बारे में पता चल जाएगा unscoped। देखें आगे क्या होता है:

2.1.1 :002 > User.first.posts.unscoped
  Post Load (0.2ms)  SELECT "posts".* FROM "posts"

=> अनकैप्ड सभी स्कोप को हटाता है जो सामान्य रूप से आपके चयन पर लागू हो सकते हैं, जिसमें (लेकिन सीमित नहीं) संघ भी शामिल हैं।

के विभिन्न प्रभावों को अधिलेखित करने के कई तरीके हैं default_scope। उस अधिकार को प्राप्त करना बहुत जल्दी जटिल हो जाता है और मैं तर्क करता हूं default_scopeकि पहली जगह का उपयोग नहीं करना, एक सुरक्षित विकल्प होगा।


2
पर ढेर करने के लिए: मैं डिफ़ॉल्ट रूप से उपयोगी केवल तभी पाया जब आप पूरी तरह से डिफ़ॉल्ट रूप से कुछ संघों को लोड करना चाहते हैं। default_scope {उत्सुक_लोड ([: श्रेणी, टिप्पणियाँ])}। तथापि!!! यदि आप Product.count की तरह इस मॉडल पर गणना क्वेरी कर रहे हैं, तो यह सभी उत्पादों के लिए संघों_को लोड करेगा। और यदि आपके पास 50K रिकॉर्ड हैं, तो आपकी गणना क्वेरी सिर्फ 15ms से 500ms में चली गई, क्योंकि जब आप चाहते हैं कि सभी गिनती है, तो आपका default_scope बाकी सब में शामिल हो जाएगा।
कोनूंग

16
मेरे लिए ऐसा लगता है कि समस्या # 2 के unscopedबजाय समस्या के साथ हैdefault_scope
कप्तान फोगेट्टी

4
@CaptainFogetti वास्तव में। मुझे अभी भी लगता है कि default_scope के संभावित नुकसान के रूप में अनकैप्ड की कमियां पेश करना एक अच्छा विचार है। अधिकांश गैर तुच्छ मामलों में default_scope का उपयोग करने से आपको अनकैप्ड का उपयोग करने की आवश्यकता होगी। यह एक दूसरा डिग्री कैविएट (बेहतर अवधि के अभाव में) है, जो एक विधि पर शोध करते समय याद रखना आसान है।
wrtsprt

1
आपके उत्तर में उपयोग के मामले में समस्या यह है कि कई मामले हैं जब आप अप्रकाशित पदों को खोजना चाहते हैं। वास्तव में, मैं तर्क दूंगा कि प्रकाशित पोस्ट खोजना एक विशेष मामला है। जब आप प्रकाशित पोस्ट चाहते हैं, केवल तभी जब कोई व्यक्ति सार्वजनिक पृष्ठ देख रहा हो। लेकिन कई बार आप अप्रकाशित पदों को देखना चाहते हैं।
बी सेवन

3
मुझे लगता है कि default_scopeजब आप कुछ छांटना चाहते हैं तो इसका एक अच्छा उपयोग है default_scope { order(:name) }:।
user2985898

9

उपयोग नहीं करने के लिए एक और कारण default_scopeहै जब आप एक मॉडल का एक उदाहरण के साथ एक 1 के लिए कई संबंध है हटा रहे हैं default_scopeमॉडल

उदाहरण के लिए विचार करें:

    class User < ActiveRecord::Base
      has_many :posts, dependent: :destroy
    end 

    class Post < ActiveRecord::Base
      default_scope { where(published: true) }
      belongs_to :user
    end

कॉलिंग user.destroyसभी पोस्ट को हटा देगा published, लेकिन यह उन पोस्ट को नहीं हटाएगा जो हैं unpublished। इसलिए डेटाबेस एक विदेशी कुंजी उल्लंघन को फेंक देगा क्योंकि इसमें रिकॉर्ड होते हैं जो उस उपयोगकर्ता को संदर्भित करता है जिसे आप निकालना चाहते हैं।


6

default_scope के खिलाफ अक्सर सिफारिश की जाती है क्योंकि यह कभी-कभी गलत तरीके से परिणाम सेट को सीमित करने के लिए उपयोग किया जाता है। Default_scope का एक अच्छा उपयोग परिणाम सेट करने के लिए आदेश देना है।

मैं wheredefault_scope के उपयोग से दूर रहूंगा और इसके लिए कोई गुंजाइश नहीं बनाऊंगा।


1
दूसरी समस्या "अनकैप्ड सभी स्कोपों ​​को हटा देता है जो सामान्य रूप से आपके चयन पर लागू हो सकते हैं, जिसमें default_scopeकेवल शामिल होने पर भी (लेकिन) तक सीमित नहीं हैं" order। का यह व्यवहार unscopedकाफी अप्रत्याशित है।
ज़ैक जू

1

मेरे लिए एक बुरा विचार नहीं है, लेकिन सावधानी के साथ इस्तेमाल किया जाना चाहिए! एक मामला है जहां मैं हमेशा एक क्षेत्र सेट होने पर कुछ रिकॉर्ड छुपाना चाहता था।

  1. अधिमानतः default_scopeडीबी डिफ़ॉल्ट मान के साथ मेल खाना चाहिए (उदाहरण के लिए: { where(hidden_id: nil) })
  2. जब आप पूरी तरह से सुनिश्चित हो जाते हैं कि आप उन रिकॉर्ड्स को दिखाना चाहते हैं, तो हमेशा वह unscopedतरीका है जो आपके काम को टाल देगाdefault_scope

तो यह निर्भर करेगा और वास्तविक जरूरतों को पूरा करेगा।


0

मैं केवल default_scopeकुछ मापदंडों को सभी स्थितियों में ascया descआदेश के क्रम में उपयोगी होना चाहता हूं । अन्यथा मैं प्लेग की तरह इससे बचता हूं

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