मल्टीटेनेंसी की एक परिभाषा के अनुसार, जब एक ऐप कई टेनेंट्स को सेवा देता है, तो इसका मतलब है कि उपयोगकर्ताओं के कुछ समूह हैं जो सॉफ़्टवेयर इंस्टेंस तक सामान्य पहुंच साझा करते हैं। मल्टीटेनेंसी का समर्थन करने वाले ऐप का एक उत्कृष्ट उदाहरण जिरा प्लेटफ़ॉर्म है, जहां प्रत्येक कंपनी का अपना सबडोमेन होता है सॉफ़्टवेयर तक पहुंचने के लिए, उदाहरण के लिए, mycompany.atlassian.net।
इस लेख में, मैं आपको मल्टीटेनेंसी के सैद्धांतिक और व्यावहारिक दोनों पहलुओं से परिचित कराऊंगा। आपके एप्लिकेशन में कई टेनेंट्स के लिए समर्थन लागू करने के कुछ लोकप्रिय दृष्टिकोणों पर चर्चा करने के बाद, मैं आपको दिखाऊंगा कि उनमें से दो को अपने रेल्स एप्लिकेशन में कैसे लागू किया जाए। हम एक साथ एक सरल ऐप बनाएंगे जिसमें कई टेनेंट्स होंगे जहां प्रत्येक टेनेंट का अपना सबडोमेन होगा।
इस लेख को पढ़ने के बाद, आप निम्न में सक्षम होंगे:
- मल्टी-टेनेंट ऐप्स के विभिन्न प्रकारों पर चर्चा करें और बताएं कि दिए गए दृष्टिकोण कब सही विकल्प है,
- कई टेनेंट्स के लिए समर्थन के साथ एक रूबी ऑन रेल्स एप्लिकेशन बनाएं, और
- रूबी ऑन रेल्स एप्लिकेशन के अंदर अपने ग्राहकों के लिए कस्टम सबडोमेन का उपयोग करें।
इस लेख का पालन करने और इसके अधिकांश लाभ प्राप्त करने के लिए रेल्स के बारे में आधारभूत ज्ञान आवश्यक है।
सिद्धांत में मल्टीटेनेंसी
जैसा कि मैंने पहले उल्लेख किया है, हम कह सकते हैं कि ऐप मल्टीटेनेंसी का समर्थन करता है जब यह उपयोगकर्ताओं के कुछ समूहों को सेवा देता है जो एप्लिकेशन की सुविधाओं तक सामान्य पहुंच साझा करते हैं। ऐसा ऐप का एक अच्छा उदाहरण एक ब्लॉगिंग प्लेटफ़ॉर्म है जहां प्रत्येक उपयोगकर्ता को मुख्य डोमेन में एक अलग सबडोमेन मिलता है। प्रत्येक ब्लॉग का अपना सबडोमेन होता है लेकिन अन्य ब्लॉग्स के समान ही सुविधाएं साझा करता है: टिप्पणियां, लेख, और प्रशासन डैशबोर्ड।
हालांकि यह सतह पर लग सकता है कि मल्टी-टेनेंट ऐप्स समान रूप से काम करते हैं, लेकिन हुड के नीचे वे मल्टीटेनेंसी आर्किटेक्चर के विभिन्न प्रकारों को लागू कर सकते हैं। आइए उनमें से सबसे लोकप्रिय और कुशल प्रकारों पर एक नज़र डालें।
डेटाबेस-रो स्तर
यदि आप अपने एप्लिकेशन में कई डेटाबेस का उपयोग नहीं करना चाहते हैं, तो आप एक ऐसे दृष्टिकोण का चयन कर सकते हैं जो एक केंद्रीय डेटाबेस पर काम करता है। डेटाबेस में प्रत्येक तालिका में tenant_id कॉलम होता है जिसका उपयोग एप्लिकेशन के अंदर किए गए प्रत्येक क्वेरी में किया जाता है ताकि दिए गए टेनेंट से संबंधित डेटा निकाला जा सके।
ऐसी संरचना में टेनेंट का सेटअप समय तेज़ होता है, कोई अतिरिक्त लागत नहीं होती है, और इस संस्करण का कार्यान्वयन हर जगह संभव है। हालांकि, हमें सावधान रहना चाहिए क्योंकि अगर हम क्वेरी में टेनेंट की आईडी शामिल करना भूल जाते हैं तो हम डेटा लीक का कारण बन सकते हैं। दिए गए उपयोगकर्ता समूहों के लिए डेटाबेस संरचना संशोधन को बनाए रखना मुश्किल होगा, इसलिए हमें इस नुकसान को ध्यान में रखना चाहिए।
स्कीमा स्तर
आपके पास अभी भी एक केंद्रीय डेटाबेस हो सकता है लेकिन प्रत्येक टेनेंट के लिए अलग-अलग टेबल और स्कीमा के साथ। डेटाबेस-रो स्तर के दृष्टिकोण के विपरीत, टेनेंट्स के बीच स्विच करते समय आपको क्वेरी को संशोधित करने के बजाय टेबल के लिए खोज पथ बदलना होगा। PostgreSQL में, आप set search_path स्टेटमेंट का उपयोग कर सकते हैं, और MySQL में स्कीमा के बीच स्विच करने के लिए use स्टेटमेंट।
इस दृष्टिकोण को चुनने से पहले, सुनिश्चित करें कि आपके DB सर्वर पर उल्लिखित स्टेटमेंट का उपयोग करना संभव है। यह भी ध्यान रखें कि नए टेनेंट्स जोड़ना अपेक्षाकृत धीमा है क्योंकि आपको डेटाबेस में एक नई स्कीमा बनानी होगी और टेबल बनानी होंगी।
डेटाबेस स्तर
यदि आप हर बार अपने एप्लिकेशन में एक नया टेनेंट जोड़ने पर एक नए डेटाबेस की लागत वहन कर सकते हैं, तो यह दृष्टिकोण आपके लिए सही हो सकता है। चर्चा की गई सभी आर्किटेक्चर में से नए टेनेंट्स जोड़ने के मामले में यह दृष्टिकोण सबसे धीमा है।
डेटा लीक का कारण बनना सबसे अधिक कठिन है क्योंकि किसी अन्य टेनेंट पर स्विच करने के लिए, आपको डेटाबेस से एक नया कनेक्शन स्थापित करना होगा। यदि आप चाहें तो आप उपयोगकर्ताओं के प्रत्येक समूह की डेटाबेस संरचना को आसानी से संशोधित भी कर सकते हैं।
एप्लिकेशन स्केलेटन बनाना
हम दो अलग-अलग एप्लिकेशन बनाएंगे: एक एक डेटाबेस के साथ मल्टीटेनेंसी द्वारा समर्थित और एक कई डेटाबेस के साथ मल्टीटेनेंसी द्वारा समर्थित। वे कई टेनेंट्स से निपटने के लिए एक अलग दृष्टिकोण का प्रतिनिधित्व करते हैं, लेकिन कॉन्फ़िगरेशन चरण समान है।
इस लेख को लिखने के समय रूबी का नवीनतम संस्करण 2.7.2 और रूबी ऑन रेल्स जेम का 6.1 RC1 है। सुनिश्चित करें कि आपके सिस्टम में रूबी का सही संस्करण स्थापित है और फ्रेमवर्क के सही संस्करण को स्थापित करने का प्रयास करें:
gem install rails -v 6.1.0.rc1अब हम निम्न कमांड के साथ प्रोजेक्ट फ़ाइलें उत्पन्न कर सकते हैं:
rails _6.1.0.rc1_ new tenantapp -d=mysqlप्रोजेक्ट डायरेक्टरी में प्रवेश करें, सर्वर चलाएं, और जांचें कि क्या आप वेलकम स्क्रीन देख सकते हैं ताकि हम जारी रख सकें:
cd tenantapp/ rails sएक डेटाबेस के साथ मल्टी-टेनेंट रेल्स एप्लिकेशन
कुछ कोड करने का समय आ गया है। लेख का यह भाग आपको दिखाएगा कि अपने रेल्स एप्लिकेशन में मल्टीटेनेंसी को कैसे लागू किया जाए। मैं एक डेटाबेस और एक स्कीमा वाले दृष्टिकोण का उपयोग करने जा रहा हूं।
योजना इस प्रकार है:
- हम रूबी और रूबी ऑन रेल्स फ्रेमवर्क के नवीनतम उपलब्ध संस्करण का उपयोग करके एक रेल्स एप्लिकेशन के लिए एक स्केलेटन बनाएंगे
- हम कुछ मॉडलों को स्कैफोल्ड करेंगे ताकि हमारे पास वह डेटा हो जिस पर हम काम कर सकें
- पिछले चरण में बनाई गई कार्यक्षमता में, हम डेटाबेस टेबल और हमारे एप्लिकेशन में कोड को अपडेट करके मल्टीटेनेंसी के लिए समर्थन जोड़ेंगे
- अंतिम चरण उपयोगकर्ताओं को अपने टेनेंट्स तक आसानी से पहुंचने की अनुमति देने के लिए कस्टम सबडोमेन के लिए समर्थन जोड़ना होगा
- हम कुछ विशेषताओं के विचारों का पता लगाएंगे जिन्हें आप बाद में अपने दम पर लागू कर सकते हैं
टेस्ट डेटा तैयार करना
मान लें कि हम एक ब्लॉग प्लेटफ़ॉर्म बना रहे हैं जहां उपयोगकर्ता कई लेखकों द्वारा प्रकाशित लेख देख सकते हैं।
मैं पहले लेखक मॉडल बनाऊंगा, जो लेखक के डेटा को संग्रहीत करेगा:
rails g scaffold author slug:string name:string description:string rake db:create rake db:migrateअब आप https://localhost:3000/authors पते पर जा सकते हैं और कुछ लेखक जोड़ सकते हैं ताकि हम बाद में उन्हें लेखों को असाइन कर सकें।
अगला कदम लेख बनाना है:
rails g scaffold article title:string content:text rake db:migrateमल्टीटेनेंसी समर्थन जोड़ना
हम जो एप्लिकेशन बना रहे हैं, उसमें लेखक हमारे टेनेंट हैं। प्रत्येक लेखक की पहुंच केवल उसके लेखों तक होनी चाहिए। जैसा कि मैंने पहले उल्लेख किया है, जब हम एक डेटाबेस और एक स्कीमा में मल्टीटेनेंसी समर्थन लागू करना चाहते हैं, तो महत्वपूर्ण आवश्यकता है कि हर मॉडल में tenant_id फ़ील्ड जोड़ा जाए जिसे हमारे टेनेंट्स द्वारा प्रबंधित किया जाना है।
डेटाबेस में उचित माइग्रेशन बनाएं
rails g migration AddTenantIdToArticle tenant_id:integer rake db:migrateउपरोक्त माइग्रेशन हमारे Article मॉडल में नया कॉलम जोड़ देगा। इस कॉलम का उपयोग किसी भी क्वेरी में वर्तमान टेनेंट को असाइन किए गए केवल डेटा को खींचने के लिए किया जाएगा।
लेख को टेनेंट को असाइन करें
इस चरण में, मैं कोड को अपडेट करने जा रहा हूं ताकि हम दिए गए लेखक को लेख असाइन कर सकें और बाद में केवल चयनित लेखक के लिए लेख प्रस्तुत कर सकें। app/controllers/articles_controller.rb खोलें और निम्नलिखित परिवर्तन जोड़ें:
class ArticlesController < ApplicationController before_action :set_article, only: [:show, :edit, :update, :destroy] before_action :set_authors, only: [:edit, :update, :new, :create] # ... private # केवल विश्वसनीय पैरामीटर्स की सूची की अनुमति दें। def article_params params.require(:article).permit(:title, :content, :tenant_id) end def set_authors @authors = Author.all end endअब हमारे व्यू में हम @authors वेरिएबल का उपयोग कर सकते हैं जिसमें हमारे ऐप में जोड़े गए लेखकों का संग्रह होता है। अब हम सेलेक्ट फ़ील्ड जोड़ सकते हैं जिसमें लेखकों के नाम होंगे और उचित tenant_id असाइन करेंगे। app/views/articles/_form.html.erb खोलें और निम्नलिखित सेक्शन जोड़ें:
<div className="field"> <%= form.label :author %> <%= form.select :tenant_id, options_from_collection_for_select(@authors, 'id', 'name', article.tenant_id), include_blank: true %> </div>आगे बढ़ें और कुछ लेखक बनाएं और फिर कुछ लेख ताकि बाद में केवल दिए गए लेखक को असाइन किए गए लेख प्रस्तुत किए जा सकें।
कस्टम सबडोमेन के लिए समर्थन जोड़ना
हमने जॉन डो नाम से लेखक बनाया और स्लग मान johndoe सेट किया। हमारा लक्ष्य https://johndoe.localhost:3000/ पते पर जाना है और दिए गए टेनेंट, इस मामले में जॉन डो से संबंधित केवल डेटा देखना है।
सबडोमेन कॉन्फ़िगरेशन
हम टेनेंट सेट होने पर लेखों को प्रबंधित और देखना चाहेंगे। हम इसे config/routes.rb फ़ाइल को अपडेट करके और आर्टिकल्स रिसोर्स की परिभाषा को कंस्ट्रेंट्स ब्लॉक में लपेटकर प्राप्त कर सकते हैं:
Rails.application.routes.draw do constraints subdomain: /.*/ do resources :articles end resources :authors endडिफ़ॉल्ट रूप से, रेल्स शीर्ष-स्तरीय डोमेन लंबाई को 1 पर सेट करता है, लेकिन हम लोकलहोस्ट का उपयोग करना चाहते हैं इसलिए इस सेटिंग को 0 पर सेट करें। हम इसे config/environments/development.rb फ़ाइल में निम्न लाइन जोड़कर कर सकते हैं:
config.action_dispatch.tld_length = 0सबडोमेन को मल्टीटेनेंसी के साथ काम करना
अब, जब सबडोमेन का उपयोग किया जाता है तो किसी भी लेखक को लेख असाइन करना संभव नहीं होना चाहिए। हमें ArticlesController के व्यवहार को बदलना होगा, और सभी लेखकों को सेट करने के बजाय, हमें उस लेखक को सेट करना होगा जिसके लिए सबडोमेन का अनुरोध किया गया था:
class ArticlesController < ApplicationController before_action :set_author before_action :set_article, only: [:show, :edit, :update, :destroy] # GET /articles # GET /articles.json def index @articles = Article.where(tenant_id: @author.id) end # ... private def set_article @article = Article.find_by!(id: params[:id], tenant_id: @author.id) end # ... def set_author @author = Author.find_by!(slug: request.subdomain) end endमैंने कंट्रोलर में कुछ बदलाव किए:
set_authorsमेथड के बजाय, मैंनेset_authorमेथड को परिभाषित किया, जो सबडोमेन के माध्यम से अनुरोधित लेखक को सेट करता है। इस मेथड कोbefore_filterमेंset_articleकॉल होने से पहले कॉल करना महत्वपूर्ण है। लेख को सेट करने का प्रयास करने से पहले लेखक को असाइन किया जाना चाहिए।- मैंने
set_articleमेथड को अपडेट किया ताकि दिए गए आईडी और असाइन किए गए लेखक के साथ लेख की खोज की जाए। हम टॉम द्वारा बनाए गए लेखों को प्रस्तुत नहीं करना चाहते जब हमारा वर्तमान टेनेंट जॉन हो। - मैंने इंडेक्स एक्शन को अपडेट किया ताकि केवल हमारे वर्तमान टेनेंट को असाइन किए गए लेखों का चयन किया जाए।
जब आप मल्टीटेनेंट ऐप पर काम करते हैं और एक डेटाबेस और एक स्कीमा का उपयोग करते हैं, तो आपको हमेशा किसी भी क्वेरी को tenant_id कॉलम द्वारा स्कोप करना याद रखना होगा; अन्यथा, आप अनुरोधित टेनेंट को असाइन नहीं किए गए डेटा प्रदान करेंगे।
कंट्रोलर अपडेट हो गया है, इसलिए अगला कदम फॉर्म व्यू को अपडेट करना है। app/views/articles/_form.html.erb फ़ाइल खोलें और पिछले सेक्शन को साधारण हिडन फ़ील्ड से बदलें:
<%= form.hidden_field :tenant_id, value: @author.id %>इन परिवर्तनों से पहले, उपयोगकर्ता फॉर्म का उपयोग करके लेख के लेखक का चयन करने में सक्षम था। अब उपयोगकर्ता वेबसाइट पते में दिए गए सबडोमेन का उपयोग करके सभी कार्यों के लिए लेखक चुन सकता है।
अब आप हमारे द्वारा बनाए गए कोड का परीक्षण कर सकते हैं। एक नया लेखक बनाएं, उदाहरण के लिए, जॉन डो नाम के साथ और स्लग johndoe। https://johndoe.localhost:3000/articles/new पते पर जाएं और एक नया लेख जोड़ें। एक नया लेख जोड़ने के बाद, आप इसे https://johndoe.localhost:3000/articles पर उपलब्ध सूची में देख सकते हैं।
बधाई हो! आपने अभी एक मल्टी-टेनेंट ऐप बनाया है जहां प्रत्येक लेखक का अपना सबडोमेन है।
आगे के सुधार
अब आप एप्लिकेशन के कोड को नई सुविधाएं जोड़कर बढ़ा सकते हैं। हमारा ब्लॉग प्लेटफ़ॉर्म सीधा है; शायद कुछ टिप्पणी अनुभाग जोड़ने का समय आ गया है? कोई फर्क नहीं पड़ता कि आप क्या कार्यक्षमता जोड़ते हैं, आपको नए मॉडल में tenant_id कॉलम जोड़ना याद रखना होगा और संसाधन को क्वेरी करते समय इसका उपयोग करना होगा।
आप एक विशेष स्कोप बना सकते हैं और इसे कंसर्न में लपेट सकते हैं:
module Tenantable extend ActiveSupport::Concern included do scope :for_author, -> (author) { where(tenant_id: author.id) } end endऔर फिर इसका उपयोग हर मॉडल में करें जिसमें टेनेंट्स के लिए डेटा होता है:
class Article < ApplicationRecord include Tenantable end author = Author.find(1) Article.for_author(author)उपरोक्त दृष्टिकोण के साथ, tenant_id कॉलम का नाम बदलने या टेनेंट-संबंधित डेटा को क्वेरी करते समय अधिक शर्तें पेश करने के मामले में आपको केवल एक स्थान को अपडेट करना होगा।
कई डेटाबेस के साथ मल्टी-टेनेंट रेल्स एप्लिकेशन
पिछले पैराग्राफ में, हमने एक रेल्स एप्लिकेशन बनाया जो एक डेटाबेस और एक स्कीमा के साथ कई टेनेंट्स का समर्थन करता है। ऐसे दृष्टिकोण का सबसे महत्वपूर्ण नुकसान डेटा लीक की उच्च संभावना है।
अच्छी खबर यह है कि रूबी ऑन रेल्स फ्रेमवर्क के नवीनतम संस्करण में कई डेटाबेस के प्रबंधन के लिए अंतर्निहित समर्थन है। मैं इसका पता लगाऊंगा और आपको दिखाऊंगा कि कई डेटाबेस और कस्टम सबडोमेन के साथ मल्टी-टेनेंट रेल्स एप्लिकेशन बनाने के लिए इसका उपयोग कैसे किया जाए।
योजना इस प्रकार है:
- हम रूबी और रूबी ऑन रेल्स फ्रेमवर्क के नवीनतम उपलब्ध संस्करण का उपयोग करके एक रेल्स एप्लिकेशन के लिए एक स्केलेटन बनाएंगे
- हम कुछ मॉडलों को स्कैफोल्ड करेंगे ताकि हमारे पास वह डेटा हो जिस पर हम काम कर सकें
- हम कस्टम सबडोमेन के लिए समर्थन जोड़ेंगे।
- हम सीखेंगे कि नए डेटाबेस बनाकर और कॉन्फ़िगर करके नए टेनेंट्स कैसे जोड़े जाएं।
- अंतिम चरण एप्लिकेशन को अपडेट करना होगा ताकि जब दिया गया सबडोमेन अनुरोधित हो तो डेटाबेस को स्विच किया जाए।
टेस्ट डेटा तैयार करना
मान लें कि हम एक ब्लॉग प्लेटफ़ॉर्म बना रहे हैं जहां उपयोगकर्ता कई लेखकों द्वारा प्रकाशित लेख देख सकते हैं। प्रत्येक लेखक का एक समर्पित डेटाबेस होगा।
Author मॉडल को स्कैफोल्डेड सुविधाओं के साथ बनाना शुरू करें जो हमें लेखकों को देखने और बनाने में मदद करेंगे:
rails g scaffold author slug:string name:string description:string rake db:create rake db:migrateअब आप https://localhost:3000/authors पर जा सकते हैं और देख सकते हैं कि रेल्स ने हमारे लिए क्या उत्पन्न किया है।
नया लेखक जोड़ना
मैंने जॉन डो नाम से एक नया लेखक बनाया और स्लग johndoe। स्लग मान का उपयोग बाद में यह पता लगाने के लिए किया जाएगा कि सबडोमेन का उपयोग करके किस लेखक की जानकारी प्रदर्शित करनी है।
चूंकि प्रत्येक लेखक का एक अलग डेटाबेस होगा, हमें जॉन के लिए मैन्युअल रूप से नया डेटाबेस जोड़ना होगा। config/database.yml खोलें और निम्नलिखित परिवर्तन जोड़ें:
development: primary: <<: *default database: tenantapp_development primary_johndoe: <<: *default database: tenantapp_johndoe_development migrations_paths: db/tenants_migrationsहम अपने टेनेंट्स द्वारा उपयोग किए जाने वाले माइग्रेशन के लिए एक अलग डायरेक्टरी का उपयोग करने जा रहे हैं। हमें उन्हें केंद्रीय डेटाबेस में नहीं चाहिए। अब आप डिफ़ॉल्ट कमांड का उपयोग करके जॉन के लिए एक डेटाबेस बना सकते हैं:
rake db:createलेख जोड़ना
अब हम कंट्रोलर और व्यू के साथ Article मॉडल को स्कैफोल्ड कर सकते हैं:
rails g scaffold article title:string content:text --database primary_johndoeमैंने रेल्स को यह बताने के लिए --database पैरामीटर पास किया कि माइग्रेशन को डिफ़ॉल्ट db/migrations डायरेक्टरी में नहीं रखा जाना चाहिए जिसका उपयोग प्राथमिक डेटाबेस द्वारा किया जाता है। अब हम माइग्रेट कमांड चला सकते हैं:
rake db:migrateअभी, हमारे पास दो स्कीमाएं हैं: db/schema.rb और db/primary_johndoe_schema.rb। यदि आप टेनेंट्स के लिए अलग-अलग टेबल बनाना चाहते हैं, तो आप इसे config/database.yml फ़ाइल में दिए गए टेनेंट के लिए एक अद्वितीय migrations_path मान सेट करके प्राप्त कर सकते हैं। इस लेख में, हम सभी टेनेंट्स के लिए समान टेबल चाहते हैं, इसलिए माइग्रेशन का पथ समान होगा।
मल्टीटेनेंसी समर्थन जोड़ना
उस एप्लिकेशन में जहां मल्टीटेनेंसी एक डेटाबेस द्वारा समर्थित है, दिए गए टेनेंट के लिए डेटा प्राप्त करने के लिए, हमें बस डेटाबेस को क्वेरी को उचित tenant_id मान के साथ अपडेट करना होगा। हमारे मामले में, प्रत्येक टेनेंट का अपना डेटाबेस है, इसलिए हमें डेटाबेस के बीच स्विच करना होगा।
रेल्स 6.1 क्षैतिज शार्डिंग के लिए अंतर्निहित समर्थन के साथ आता है। शार्ड एक क्षैतिज डेटा विभाजन है जिसमें कुल डेटासेट का एक सबसेट होता है। हम सभी लेखकों के लेखों को एक डेटाबेस में एक टेबल में संग्रहीत कर सकते थे, लेकिन शार्डिंग के लिए धन्यवाद, हम डेटा को समान संरचना वाली कई टेबलों में विभाजित कर सकते हैं लेकिन अलग-अलग डेटाबेस में रखे गए हैं।
आइए सभी मॉडलों के लिए पैरेंट क्लास में हमारे शार्ड्स को परिभाषित करें। वे app/models/application_record.rb के तहत संग्रहीत हैं:
ActiveRecord::Base.connected_to(role: :reading, shard: :johndoe) do Article.all # जॉन द्वारा बनाए गए सभी लेख प्राप्त करें endconnected_to ब्लॉक में हमारे कॉल को लपेटे बिना, डिफ़ॉल्ट शार्ड का उपयोग किया जाएगा। आगे बढ़ने से पहले, हमें एक और बदलाव करना होगा। चूंकि सभी शार्ड्स समान डेटा संरचना साझा करते हैं, हम app/models/primary_johndoe_record.rb मॉडल को हटा सकते हैं जो स्वचालित रूप से बनाया गया था जब हम लेखों को स्कैफोल्ड कर रहे थे।
हमें app/models/article.rb मॉडल को भी संपादित करना होगा और पैरेंट क्लास को PrimaryJohndoeRecord से ApplicationRecord में बदलना होगा:
class Article < ApplicationRecord endअधिक टेनेंट्स जोड़ना
वर्तमान में, हमारे डेटाबेस में केवल एक लेखक है। अपने टेनेंट्स (डेटाबेस) के बीच स्विच करने की कार्यक्षमता का परीक्षण करने के लिए, हमें एक और लेखक जोड़ना होगा। https://localhost:3000/authors/new पते पर जाएं और एक नया लेखक जोड़ें। मैंने टिम डो नाम से लेखक को स्लग timdoe के साथ जोड़ा।
नए लेखक के लिए हमारे पास एक रिकॉर्ड है, इसलिए हमें एक नया डेटाबेस परिभाषित करना होगा:
development: primary: <<: *default database: tenantapp_development primary_johndoe: <<: *default database: tenantapp_johndoe_development migrations_paths: db/tenants_migrations primary_timdoe: <<: *default database: tenantapp_timdoe_development migrations_paths: db/tenants_migrationsअब एक नया डेटाबेस बनाएं और माइग्रेशन चलाएं:
rake db:create rake db:migrateअंतिम चरण ApplicationRecord मॉडल को अपडेट करना और एक नया शार्ड परिभाषित करना है:
class ApplicationRecord < ActiveRecord::Base self.abstract_class = true connects_to shards: { default: { writing: :primary, reading: :primary }, johndoe: { writing: :primary_johndoe, reading: :primary_johndoe }, timdoe: { writing: :primary_timdoe, reading: :primary_timdoe }, } endअब आप प्रत्येक लेखक के लिए लेख बना सकते हैं:
ActiveRecord::Base.connected_to(role: :writing, shard: :johndoe) do Article.create!(title: 'Article from John', content: 'content') end ActiveRecord::Base.connected_to(role: :writing, shard: :timdoe) do Article.create!(title: 'Article from Tim', content: 'content') endकस्टम सबडोमेन के लिए समर्थन जोड़ना
हम अभी तक दिए गए लेखक के लिए लेखों की सूची पर नहीं जा सकते क्योंकि हम नहीं जानते कि हमें कब जॉन के लेख दिखाने चाहिए और कब टिम के। हम कस्टम सबडोमेन को लागू करके इस समस्या को हल करेंगे। जब https://johndoe.localhost:3000/articles पर जाएंगे, तो हमें जॉन के लेख दिखाई देंगे, और जब https://timdoe.localhost:3000/articles पर जाएंगे तो टिम के लेख।
सबडोमेन कॉन्फ़िगरेशन
हम टेनेंट सेट होने पर लेखों को प्रबंधित और देखना चाहेंगे। हम इसे config/routes.rb फ़ाइल को अपडेट करके और आर्टिकल्स रिसोर्स की परिभाषा को कंस्ट्रेंट्स ब्लॉक में लपेटकर प्राप्त कर सकते हैं:
Rails.application.routes.draw do constraints subdomain: /.*/ do resources :articles end resources :authors endडिफ़ॉल्ट रूप से, रेल्स शीर्ष-स्तरीय डोमेन लंबाई को 1 पर सेट करता है, लेकिन हम लोकलहोस्ट का उपयोग करना चाहते हैं इसलिए इस सेटिंग को 0 पर सेट करें। हम इसे config/environments/development.rb फ़ाइल में निम्न लाइन जोड़कर कर सकते हैं:
config.action_dispatch.tld_length = 0सबडोमेन को मल्टीटेनेंसी के साथ काम करना
वर्तमान टेनेंट के लिए डेटाबेस पढ़ने को मानकीकृत करने के लिए, मैं Tenantable नामक एक कंट्रोलर कंसर्न बनाऊंगा। यह read_with_tenant मेथड प्रदान करता है, जो एक ब्लॉक स्वीकार करता है और इसे अनुरोधित टेनेंट के संदर्भ में निष्पादित करता है:
module Tenantable extend ActiveSupport::Concern private def read_with_tenant(&block) author = Author.find_by!(slug: request.subdomain) ActiveRecord::Base.connected_to(role: :reading, shard: author.slug.to_sym) do block.call end end endइस फ़ाइल को app/controllers/concerns/tenantable.rb के रूप में सहेजें और ArticlesController में शामिल करें:
class ArticlesController < ApplicationController include Tenantable before_action :set_article, only: [:show, :edit, :update, :destroy] def index read_with_tenant do @articles = Article.all end end # ... endअब आप https://johndoe.localhost:3000/articles या https://timdoe.localhost:3000/articles पर जा सकते हैं, और आपको सूची में अलग-अलग लेख प्रदर्शित दिखाई देंगे।
यदि आप फॉर्म का उपयोग करके नए लेख बनाना चाहते हैं, तो आपको write_with_tenant नामक एक नया मेथड परिभाषित करना होगा और ArticlesController के अंदर Tenantable कंसर्न और मेथड्स को तदनुसार अपडेट करना होगा।
आगे के सुधार
ऊपर प्रस्तुत दृष्टिकोण केवल एक सरल रैपर मेथड है जो दिए गए डेटाबेस कनेक्शन के भीतर ब्लॉक में लिपटे कोड को निष्पादित करता है। इसे और अधिक सार्वभौमिक बनाने के लिए, आप एक मिडलवेयर बना सकते हैं जो किसी भी कोड को निष्पादित करने से पहले सबडोमेन को पार्स करेगा और कनेक्शन स्थापित करेगा:
ActiveRecord::Base.establish_connection(:primary_timdoe)अंतिम समाधान आपकी आवश्यकताओं और उन स्थानों की संख्या पर निर्भर करता है जहां आप किसी विशिष्ट टेनेंट को असाइन किए गए डेटा का उपयोग करना चाहते हैं।
सारांश
बधाई हो, आपने अभी मल्टी-टेनेंट रेल्स एप्लिकेशन के दो संस्करण बनाए हैं और एक आधुनिक वेब एप्लिकेशन में कई टेनेंट्स से निपटने के विभिन्न तरीकों के बारे में ज्ञान प्राप्त किया है।
आइए जल्दी से सारांशित करें कि हमने इस लेख के दौरान क्या सीखा:
- वेब एप्लिकेशन में तीन प्राथमिक मल्टी-टेनेंसी स्तर हैं - डेटाबेस-रो, स्कीमा, और डेटाबेस स्तर।
- प्रत्येक दृष्टिकोण के अपने फायदे और नुकसान हैं, और आपकी पसंद हार्डवेयर संभावनाओं और टेनेंट जानकारी के अलगाव के स्तर पर निर्भर करती है।
- किसी भी बाहरी लाइब्रेरी के बिना रूबी ऑन रेल्स फ्रेमवर्क के भीतर सभी मल्टी-टेनेंसी स्तरों को लागू करना संभव है।
- रूबी ऑन रेल्स कस्टम सबडोमेन का बॉक्स से बाहर समर्थन करता है, इसलिए यह एक मल्टी-टेनेंट एप्लिकेशन के लिए एक आदर्श जोड़ है जहां प्रत्येक टेनेंट को अपना सबडोमेन असाइन किया जा सकता है।
मुझे आशा है कि आपको यह लेख पढ़ने और मल्टी-टेनेंट रूबी ऑन रेल्स एप्लिकेशन बनाने में मज़ा आया।
P.S. यदि आप रूबी मैजिक पोस्ट को प्रेस से निकलते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूज़लेटर की सदस्यता लें और कभी भी एक भी पोस्ट मिस न करें!