हम हनीबैजर में एक मील के पत्थर पर पहुँच गए हैं। हमारे सेल्स पेज अब हमारे मुख्य रेल्स ऐप का हिस्सा नहीं हैं। यह सालों से मेरी विशलिस्ट में था, लेकिन कभी सर्वोच्च प्राथमिकता नहीं रहा।
समस्या
इस माइग्रेशन के हिस्से के रूप में, मुझे विशेष रीडायरेक्ट लिंक बनाने के लिए URI.join का उपयोग करना पड़ा। लेकिन मुझे जल्दी ही एक समस्या का सामना करना पड़ा - URI.join मेरी अपेक्षा के अनुरूप व्यवहार नहीं कर रहा था।
मैं उम्मीद कर रहा था कि यह पाथ फ्रैगमेंट्स को लेकर उन्हें जोड़ देगा:
# मेरी अपेक्षा थी। लेकिन ऐसा नहीं हुआ।
URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/plans/change"
लेकिन join मेथड ने कुछ अजीब किया - इसने मेरे एक पाथ फ्रैगमेंट को छोड़ दिया, केवल अंतिम "change" का उपयोग किया:
# वास्तव में क्या हुआ
URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/change"
आखिर यह ऐसा व्यवहार क्यों करता है?
गलतफहमी
दरअसल, मैं URI.join से Array#join के विशेष संस्करण जैसा व्यवहार अपेक्षित कर रहा था - URL फ्रैगमेंट्स लेकर उन्हें जोड़कर पूरा URL बनाना।
लेकिन यह ऐसा नहीं करता। बड़ा आश्चर्य!
यदि हम join मेथड के कोड को देखें, तो पता चलता है कि यह सभी आर्गुमेंट्स पर पुनरावृति करता है और प्रत्येक पर merge कॉल करता है:
# File uri/rfc2396_parser.rb, line 236
def join(*uris)
uris[0] = convert_to_uri(uris[0])
uris.inject :merge
end
merge मेथड दो काम करता है:
- यह आपके स्ट्रिंग जैसे "pages" को एक सापेक्ष URI ऑब्जेक्ट में बदलता है।
- यह RFC2396, सेक्शन 5.2 में निर्दिष्ट तरीके से सापेक्ष URI को बेस URI पर हल करने का प्रयास करता है।
यह तो ठीक है, लेकिन इससे मेरी अप्रत्याशित व्यवहार की व्याख्या कैसे होती है?
URI.join("https://www.honeybadger.io", "plans", "change")
# => "https://www.honeybadger.io/change"
चलिए चरण-दर-चरण समझते हैं। उपरोक्त कोड इसके समतुल्य है:
URI.parse("https://www.honeybadger.io/plans").merge("change")
यह कोड सापेक्ष URI "change" को निरपेक्ष URI "https://www.honeybadger.io/plans" के विरुद्ध हल करने का प्रयास करता है।
यह RFC2396, सेक्शन 5.2.6 का पालन करता है, जिसमें कहा गया है:
a) बेस URI के पाथ कंपोनेंट के अंतिम सेगमेंट को छोड़कर सभी को बफर में कॉपी किया जाता है। यानी अंतिम (सबसे दाएं) स्लैश के बाद के किसी भी वर्ण को बाहर रखा जाता है।
b) रेफरेंस का पाथ कंपोनेंट बफर स्ट्रिंग में जोड़ा जाता है।
चलिए साथ चलते हैं:
- निरपेक्ष URL के अंतिम सेगमेंट को छोड़कर सब कुछ कॉपी करें। इससे मुझे
"https://www.honeybadger.io/"मिलता है - सापेक्ष पाथ जोड़ें, परिणाम:
"https://www.honeybadger.io/change"
दुनिया फिर से समझ में आने लगी!
निष्कर्ष
हालांकि URI.join का उपयोग विभिन्न पाथ फ्रैगमेंट्स से URL बनाने के लिए किया जा सकता है, लेकिन यह वास्तव में इसके लिए डिज़ाइन नहीं किया गया है। यह RFC में निर्दिष्ट मानकों के अनुसार URIs को पुनरावर्ती रूप से मर्ज करने के लिए डिज़ाइन किया गया है - जो थोड़ा अधिक जटिल काम है।
जहां तक मेरी व्यक्तिगत परियोजना का सवाल है - हमारे नए सेल्स पेजों पर रीडायरेक्ट के लिए URL बनाना - मैंने बस Array#join का उपयोग किया। :)
संपादन 8/12/2016: इस लेख के प्रकाशन के बाद मुझे कुछ ट्वीट्स मिले जिनमें File.join उपयोग करने का सुझाव दिया गया था। इसका लाभ डबल स्लैश से बचना है, यानी /my//path लेकिन यह विंडोज जैसे OS पर टूट जाएगा, जहां पाथ सेपरेटर फॉरवर्ड-स्लैश नहीं होता।