आम तौर पर, वैश्विक चर खराब होते हैं। लेकिन कभी-कभी, सही जगह पर एक वैश्विक आपके कोड को बहुत आसान बना सकता है।
रेल में, आप अनुरोध के दौरान एक बार डेटा सेट कर सकते हैं, लेकिन इसे अपने ऐप की प्रत्येक परत में उपयोग करें। कौन सा उपयोगकर्ता अनुरोध कर रहा है? उनके पास क्या अनुमति है? किस डेटाबेस कनेक्शन का उपयोग किया जाना चाहिए?
यह जानकारी आपके पूरे कोड में उपलब्ध होनी चाहिए, इसलिए इसे हर जगह पास करना शोर का एक गुच्छा होगा। लेकिन रूबी ग्लोबल वैरिएबल का उपयोग करना, या क्लास वैरिएबल सेट करना, अपनी समस्याएं पैदा करेगा। एकाधिक थ्रेड इसे अधिलेखित कर सकते हैं, और आप एक बड़ी गड़बड़ी, और शायद अप्राप्य रूप से खराब डेटा के साथ समाप्त हो जाएंगे।
आपको कुछ ऐसा चाहिए जो वैश्विक हो, लेकिन सिर्फ आपके अनुरोध के लिए .
सादा रूबी रास्ता
आमतौर पर, आप इसे Thread.current[]
. के साथ हैंडल करते हुए देखेंगे . यह इस तरह दिखता है:
Thread.current[:current_user] = user
यह काफी सरल है। यह एक अच्छा समाधान है। लेकिन इसकी दो बड़ी कमियां हैं:
-
कोई आपके डेटा को गलती से अधिलेखित कर सकता है।
क्या होगा अगर दो लोगों ने एक ही चाबी उठाई? आप एक दूसरे के डेटा पर स्टंप करेंगे। और यदि आप उपयोगकर्ताओं की तरह कुछ संग्रहीत कर रहे हैं, तो यह गंभीर रूप से खराब होगा। आपके अपने ऐप्स में, यह शायद कोई समस्या नहीं होगी। लेकिन अगर आप रत्न लिख रहे हैं, या आपका रेल ऐप बड़ा और गड़बड़ है, तो आपको इस बारे में सोचने की ज़रूरत है।
-
यह अच्छी तरह से संरचित नहीं है।
Thread.current[]
डेटा का सिर्फ एक बड़ा बैग है। आप इसे आसानी से दस्तावेज नहीं कर सकते। यदि आप यह जानना चाहते हैं कि आप इसमें से क्या निकाल सकते हैं, तो आपको यह खोजना होगा कि आपने इसमें क्या डाला है।बेशक, यदि आप पर्याप्त वैश्विक डेटा को दूर कर रहे हैं कि यह एक समस्या है, तो आपको
Thread.current[]
से अधिक चिंता करने की आवश्यकता है संरचना की कमी है। लेकिन यह अभी भी ध्यान में रखने वाली बात है।
तो, क्या Thread.current[]
. से बेहतर समाधान है? ? जैसा कि आप कल्पना कर सकते हैं, रेल स्वयं बहुत सारे अनुरोध-स्थानीय डेटा का प्रबंधन करता है। और अच्छाइयों का डिब्बा जो कि ActiveSupport है, का अनुसरण करने के लिए एक अलग पैटर्न है।
रेल मार्ग
यदि आप ActiveSupport के माध्यम से खुदाई करते हैं, तो आप ActiveSupport::PerThreadRegistry
में भाग सकते हैं . आप शायद नाम से बता सकते हैं कि यह वही है जिसे हम ढूंढ रहे हैं।
ActiveSupport::PerThreadRegistry
. के साथ , पहले वाला उदाहरण इस तरह दिखेगा:
class RequestRegistry
extend ActiveSupport::PerThreadRegistry
attr_accessor :current_user, :current_permissions
end
RequestRegistry.current_user = user
RequestRegistry.current_user # => user
यह थोड़ा और काम है। लेकिन ActiveSupport::PerThreadRegistry
. के साथ :
-
आपके पास दस्तावेज रखने की जगह है। आपकी कक्षा को देखने वाला कोई भी व्यक्ति ठीक-ठीक जान जाएगा कि आप किस वैश्विक डेटा की अपेक्षा कर रहे हैं और वे किस वैश्विक डेटा का उपयोग कर सकते हैं।
-
आपको एक अच्छा दिखने वाला एपीआई मिलता है। वास्तव में, ऐसा लगता है कि आप केवल वर्ग चर सेट कर रहे हैं। यदि आपको धागों के बारे में चिंता नहीं करनी होती तो शायद आप यही कर रहे होते।
-
आपके द्वारा कक्षा में सेट किया गया कोई भी डेटा नाम स्थान पर रखा जाएगा। आपको
RequestRegistry.current_user
के बारे में चिंता करने की ज़रूरत नहीं हैPhoneNumberApiRegistry.current_user
. से टकराना , उनके साथ पूरी तरह से अलग व्यवहार किया जाता है।
रेल ActiveSupport::PerThreadRegistry
. का उपयोग करती है आंतरिक रूप से, ActiveRecord कनेक्शन हैंडलिंग जैसी चीज़ों के लिए, EXPLAIN क्वेरी संग्रहीत करना, और ActiveSupport::Notifications। इसलिए यदि आप PerThreadRegistry
. की शक्ति के अधिक अच्छे उदाहरणों की तलाश कर रहे हैं , रेल अपने आप में शुरू करने के लिए एक बेहतरीन जगह है।
जब थ्रेड और अनुरोध मेल नहीं खाते
कुछ रेल सर्वरों के लिए, एक थ्रेड एकाधिक अनुरोधों को संभालता है। इसका मतलब है कि आपने जो कुछ भी PerThreadRegistry
. में डाला है अगले अनुरोध के लिए चारों ओर चिपके रहेंगे। शायद यह वह नहीं है जो आप चाहते हैं।
आप वह कर सकते हैं जो रेल करता है, और आपके द्वारा PerThreadRegistry
में डाली गई चीज़ों को साफ़ करें आपके द्वारा उनके साथ किए जाने के बाद। आपने वहां जो डाला है उसके आधार पर, हो सकता है कि आप वैसे भी ऐसा कर रहे हों।
टिप्पणियों में, मैटबी एक आसान समाधान की ओर इशारा करता है:request_store. यह Thread.current[]
की तरह काम करता है , लेकिन प्रत्येक अनुरोध के बाद स्वयं को साफ़ करता है।
यह किसी के लिए PerRequestRegistry
. बनाने के लिए दरवाजा खुला छोड़ देता है , जो PerThreadRegistry
. के API के साथ request_store की सुरक्षा को जोड़ती है . अगर किसी ने पहले ही ऐसा कर लिया है, तो मुझे इसके बारे में सुनना अच्छा लगेगा!
इसे आज़माएं
वैश्विक डेटा खराब हो सकता है। बहुत सारे ग्लोबल्स जल्दी से अप्राप्य कोड की ओर ले जा सकते हैं।
लेकिन अगर पूरे अनुरोध के लिए डेटा को केंद्रीय स्थान पर रखना समझ में आता है, तो Thread.current[]
से आगे जाएं . ActiveSupport::PerThreadRegistry
दें या रिक्वेस्ट_स्टोर एक शॉट। यदि और कुछ नहीं, तो यह वैश्विक डेटा के साथ व्यवहार करना थोड़ा कम जोखिम भरा बना देगा।