आज की पोस्ट में, हम structure.sql
. का उपयोग करने के महत्वपूर्ण अंतर और लाभों को कवर करेंगे बनाम डिफ़ॉल्ट schema.rb
आपके रूबी ऑन रेल्स एप्लिकेशन में स्कीमा प्रारूप। डेटा-संचालित दुनिया में, अपने डेटाबेस की सभी समृद्ध सुविधाओं का दोहन करने का तरीका जानने से एक सफल और असफल उद्यम के बीच अंतर आ सकता है।
दो प्रारूपों के बीच मुख्य अंतर को स्पष्ट करने के बाद, हम यह बताएंगे कि कैसे structure.sql
पर स्विच किया जाए और प्रदर्शित करें कि यह डेटा अखंडता के साथ-साथ डेटाबेस कार्यक्षमता को सुनिश्चित करने में कैसे मदद कर सकता है जिसे आप अन्यथा संरक्षित करने में सक्षम नहीं हो सकते हैं।
पोस्ट में, मैं एक रेल ऐप का उदाहरण दूंगा जो structure.sql
. का उपयोग करता है PostgreSQL डेटाबेस के साथ, लेकिन अंतर्निहित अवधारणाओं को अन्य डेटाबेस में भी स्थानांतरित किया जा सकता है। कोई भी वास्तविक-विश्व वेब एप्लिकेशन इसका समर्थन करने के लिए एक विश्वसनीय डेटाबेस के बिना वास्तव में पूर्ण नहीं है।
आगे की हलचल के बिना, आइए इसमें गोता लगाएँ!
schema.rb और structure.sql के बीच अंतर
रूबी ऑन रेल्स प्रोजेक्ट शुरू करते समय आपको सबसे पहले जो काम करना है, वह है डेटाबेस माइग्रेशन चलाना। उदाहरण के लिए, यदि आप एक उपयोगकर्ता मॉडल उत्पन्न करते हैं, तो रेल अनिवार्य रूप से आपको माइग्रेशन चलाने के लिए कहेगा, जो एक schema.rb
बनाएगा। तदनुसार फाइल करें:
rails g model User first_name:string last_name:string
रेल निम्नलिखित माइग्रेशन उत्पन्न करेगी:
class CreateUsers < ActiveRecord::Migration[6.0]
def change
create_table :users do |t|
t.string :first_name
t.string :last_name
t.timestamps
end
end
end
एक बार माइग्रेशन निष्पादित हो जाने पर, आप पाएंगे कि रेल ने एक schema.rb
उत्पन्न किया है आपके लिए फ़ाइल:
ActiveRecord::Schema.define(version: 2019_12_14_074018) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
यह schema.rb
फ़ाइल अपेक्षाकृत बुनियादी अनुप्रयोगों और उपयोग के मामलों के लिए शानदार है।
यहाँ ध्यान देने योग्य दो मुख्य बातें हैं:
- यह आपके डेटाबेस का रूबी प्रतिनिधित्व है;
schema.rb
रूबी का उपयोग करके डेटाबेस का निरीक्षण करके और इसकी संरचना को व्यक्त करके बनाया गया है। - यह डेटाबेस-अज्ञेयवादी है (यानी आप SQLite, PostgreSQL, MySQL या किसी अन्य डेटाबेस का उपयोग करते हैं जो रेल का समर्थन करता है, सिंटैक्स और संरचना काफी हद तक समान रहेगी)
हालांकि, एक समय ऐसा भी आ सकता है जब यह रणनीति आपके बढ़ते ऐप के लिए बहुत सीमित हो जाती है।
मान लीजिए, उदाहरण के लिए, आपके पास सैकड़ों या हजारों माइग्रेशन फ़ाइलें हैं।
यदि आपको एक नई उत्पादन प्रणाली को तेजी से स्पिन करने की आवश्यकता है, तो आप एक ऐसे परिदृश्य का सामना कर सकते हैं जहां उन सभी को क्रम में चलाने में बहुत अधिक समय लगता है। या आपको ऐसी स्थिति का सामना करना पड़ सकता है जहां कुछ माइग्रेशन में कोड होता है जिसे आपके डेटाबेस के पुराने संस्करण पर निष्पादित किया जाना था, लेकिन यह अब वर्तमान संस्करण पर निष्पादन योग्य नहीं है। आपके पास ऐसी स्थिति हो सकती है जहां कुछ डेटा मान्यताओं के साथ माइग्रेशन लिखे गए थे जो अब मान्य नहीं हैं, जिससे माइग्रेशन विफल हो जाएगा।
ये सभी परिदृश्य आपके एप्लिकेशन के एक नए इंस्टेंस को कुशलतापूर्वक स्थापित करने से रोकते हैं - चाहे वह उत्पादन में हो या टीम के नए सदस्य के लिए - एक साधारण rails db:create db:migrate
के साथ। आज्ञा। यदि ऐसा होता, तो आप एक सही डेटाबेस स्कीमा के साथ गति कैसे प्राप्त करते?
निश्चित रूप से, एक तरीका यह होगा कि वापस जाएं और सभी टूटे हुए पलायन को ठीक करें। यह कभी भी एक बुरा विचार नहीं है!
यदि वापस जाना और कई माइग्रेशन को ठीक करना बहुत महंगा है, तो दूसरा तरीका rails db:setup
चलाना होगा। काम। यह कार्य आपके schema.rb
. से एक डेटाबेस स्कीमा उत्पन्न करेगा फ़ाइल। हालाँकि, क्या होगा यदि आपके डेटाबेस में जटिल तर्क है जो schema.rb
. में प्रदर्शित नहीं है आपके डेटाबेस का प्रतिनिधित्व?
सौभाग्य से, रेल एक विकल्प प्रदान करता है:structure.sql
structure.sql
schema.rb
. से अलग है निम्नलिखित तरीकों से:
- यह डेटाबेस संरचना की एक सटीक प्रतिलिपि की अनुमति देता है। एक टीम के साथ काम करते समय यह महत्वपूर्ण है, साथ ही यदि आपको
rails db:setup
से उत्पादन में तेजी से एक नया डेटाबेस उत्पन्न करने की आवश्यकता है कार्य। - यह उन्नत डेटाबेस सुविधाओं की जानकारी को संरक्षित करने की अनुमति देता है। उदाहरण के लिए, यदि आप PostgreSQL का उपयोग कर रहे हैं, तो यह विचारों, भौतिक विचारों, कार्यों, बाधाओं आदि के उपयोग को सक्षम बनाता है।
एक बार जब कोई एप्लिकेशन एक निश्चित परिपक्वता स्तर तक पहुंच जाता है, तो हमें दक्षता बढ़ाने, डेटा की शुद्धता को बनाए रखने और तेज-तर्रार प्रदर्शन सुनिश्चित करने के लिए पुस्तक में हर तरकीब का उपयोग करना होगा। structure.sql
का उपयोग करना रेल डेटाबेस के व्यवहार को प्रबंधित करने के लिए उपयोगकर्ताओं को ऐसा करने की अनुमति देता है।
schema.rb
से स्विच करना करने के लिए structure.sql
schema.rb
. से परिवर्तन करना करने के लिए structure.sql
अपेक्षाकृत सीधी प्रक्रिया है। आपको बस निम्न पंक्ति को config/application.rb
में सेट करना है :
module YourApp
class Application < Rails::Application
config.load_defaults 6.0
# Add this line:
config.active_record.schema_format = :sql
end
end
फिर, rails db:migrate
चलाएं और आपको फ़ाइल को db/structure.sql
. में देखना चाहिए . वोइला! आपके द्वारा उपयोग किए जा रहे डेटाबेस के लिए विशिष्ट उपकरण का उपयोग करके रेल डेटाबेस संरचना को डंप कर देगा (पोस्टग्रेएसक्यूएल के मामले में, वह उपकरण है pg_dump
, MySQL या MariaDB के लिए, इसमें SHOW CREATE TABLE
का आउटपुट होगा प्रत्येक तालिका के लिए, आदि)। यह सुनिश्चित करने की सलाह दी जाती है कि यह फ़ाइल संस्करण नियंत्रण में है ताकि आपकी बाकी टीम की डेटाबेस संरचना समान हो।
उस फ़ाइल को पहली नज़र में देखना कठिन हो सकता है:schema.rb
फ़ाइल केवल 25 पंक्तियों की थी, जबकि structure.sql
फ़ाइल एक विशाल 109 लाइनें है! इतनी बड़ी फ़ाइल ऐप के विकास में क्या लाभ जोड़ सकती है?
डेटाबेस-स्तर की बाधाओं को जोड़ना
ActiveRecord रेल का उपयोग करने के मेरे पसंदीदा भागों में से एक है। यह आपको डेटाबेस को इस तरह से क्वेरी करने की अनुमति देता है जो स्वाभाविक लगता है, लगभग बोली जाने वाली भाषा की तरह। उदाहरण के लिए, यदि आप किसी कंपनी के डैन नाम के सभी उपयोगकर्ताओं को ढूंढना चाहते हैं, तो ActiveRecord आपको निम्न की तरह एक क्वेरी चलाने की अनुमति देता है:
company = Company.find(name: 'Some Company')
# Reads just like in a natural language!
company.users.where(first_name: 'Dan')
हालांकि कुछ ऐसे मामले हैं जिनमें ActiveRecord कम हो जाता है। उदाहरण के लिए, मान लें कि आपके पास अपने उपयोगकर्ता मॉडल पर निम्नलिखित सत्यापन है:
class User < ApplicationRecord
validate :name_cannot_start_with_d
private
def name_cannot_start_with_d
if first_name.present? && first_name[0].downcase == 'd'
errors.add(:first_name, "cannot start with the letter 'D'")
end
end
end
यदि आप 'Dan' नाम का उपयोगकर्ता बनाने का प्रयास करते हैं, तो सत्यापन के चलने पर आपको एक त्रुटि दिखाई देनी चाहिए:
User.create!(first_name: 'Dan')
Traceback (most recent call last):
ActiveRecord::RecordInvalid (Validation failed: First name cannot start with the letter 'D')
यह ठीक है, लेकिन मान लें कि आपने या आपकी टीम के किसी सदस्य ने ActiveRecord के सत्यापन को दरकिनार कर डेटा बदल दिया है:
u = User.create(first_name: 'Pan')
# The update_attribute method bypasses ActiveRecord validations
u.update_attribute :first_name, 'Dan'
u.first_name
=> "Dan"
जैसा कि दिखाया गया है, सत्यापन को बायपास करना बहुत आसान है।
यह हमारे आवेदन के लिए विनाशकारी परिणाम हो सकता है। ActiveRecord एक आशीर्वाद के साथ-साथ एक अभिशाप भी हो सकता है - जबकि इसमें एक बहुत ही साफ और प्राकृतिक डीएसएल है जो इसे काम करने में खुशी देता है, मॉडल-स्तरीय सत्यापन को लागू करते समय यह अक्सर अत्यधिक अनुमोदित होता है। समाधान, जैसा कि आप पहले से ही जानते हैं, डेटाबेस-स्तर की बाधाओं को जोड़ना है।
rails g migration AddFirstNameConstraintToUser
यह एक फ़ाइल उत्पन्न करेगा जिसे आप 'D' अक्षर से शुरू होने वाले पहले नामों को अस्वीकार करने के लिए तर्क के साथ संपादित कर सकते हैं:
class AddFirstNameConstraintToUser < ActiveRecord::Migration[6.0]
def up
execute "ALTER TABLE users ADD CONSTRAINT name_cannot_start_with_d CHECK (first_name !~* '^d')"
end
def down
execute "ALTER TABLE users DROP CONSTRAINT IF EXISTS name_cannot_start_with_d"
end
end
ध्यान दें कि यह बहुत है कोड जोड़ने के लिए महत्वपूर्ण है जो सफलतापूर्वक माइग्रेशन को वापस कर देता है। उपरोक्त उदाहरण में, मेरे पास up
है और down
निर्देश। up
माइग्रेशन चलने पर विधि निष्पादित हो जाती है, down
जब माइग्रेशन वापस ले लिया जाता है तो निष्पादित हो जाता है। अपनी डेटाबेस संरचना को ठीक से पूर्ववत किए बिना, आपको बाद में कुछ मैनुअल हाउस-क्लीनिंग करनी पड़ सकती है। मेरा सुझाव है कि हमेशा एक ऐसी माइग्रेशन फ़ाइल रखें जिसे up
both दोनों तरह से निष्पादित किया जा सके और down
भविष्य के सिरदर्द से बचने के लिए।
अब, माइग्रेशन चलाएँ और जाँचें कि क्या आप उस बाधा को बायपास कर सकते हैं:
rails db:migrate
user = User.create first_name: 'Pan'
user.update_attribute :first_name, 'Dan'
ActiveRecord::StatementInvalid (PG::CheckViolation: ERROR: new row for relation "users" violates check constraint "name_cannot_start_with_d")
DETAIL: Failing row contains (2, Dan, null, 2019-12-14 09:40:11.809358, 2019-12-14 09:40:41.658974).
उत्तम! हमारी बाधा इरादा के अनुसार काम कर रही है। भले ही, किसी भी कारण से, हम ActiveRecord के सत्यापन को दरकिनार कर दें, फिर भी हम अपने डेटा अखंडता को बनाए रखने के लिए डेटाबेस—हमारे अंतिम गोलकीपर— पर भरोसा कर सकते हैं।
इसका structure.sql
से क्या लेना-देना है? ?
यदि आप इसे देखें, तो आप देखेंगे कि निम्नलिखित जोड़ा गया था:
CREATE TABLE public.users (
id bigint NOT NULL,
first_name character varying,
last_name character varying,
created_at timestamp(6) without time zone NOT NULL,
updated_at timestamp(6) without time zone NOT NULL,
CONSTRAINT name_cannot_start_with_d CHECK (((first_name)::text !~* '^d'::text)));
आपकी बाधा स्कीमा के भीतर ही है!
जबकि schema.rb
डेटाबेस-स्तर की बाधाओं का भी समर्थन करता है, यह याद रखना महत्वपूर्ण है कि यह आपके डेटाबेस द्वारा समर्थित हर चीज को व्यक्त नहीं करता है जैसे कि ट्रिगर, अनुक्रम, संग्रहीत कार्यविधियाँ या जाँच बाधाएँ। उदाहरण के लिए, समान सटीक माइग्रेशन के साथ आपकी स्कीमा फ़ाइल का यही होगा (AddFirstNameConstraintToUser
) यदि आप केवल schema.rb
. का उपयोग करने वाले थे :
ActiveRecord::Schema.define(version: 2019_12_14_074018) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
create_table "users", force: :cascade do |t|
t.string "first_name"
t.string "last_name"
t.datetime "created_at", precision: 6, null: false
t.datetime "updated_at", precision: 6, null: false
end
end
फ़ाइल नहीं बदली है! बाधा नहीं जोड़ी गई थी।
यदि आप अपने प्रोजेक्ट पर काम करने के लिए एक नए डेवलपर को शामिल करते हैं, तो आप संभावित रूप से विभिन्न डेटाबेस नियमों के तहत काम कर रहे होंगे।
कमिटिंग structure.sql
टू वर्जन कंट्रोल से यह सुनिश्चित करने में मदद मिलेगी कि आपकी टीम एक ही पेज पर है। अगर आप rails db:setup
run चलाते हैं एक structure.sql
having होना फ़ाइल, आपके डेटाबेस की संरचना में उपरोक्त बाधा होगी। schema.rb
. के साथ ऐसी कोई गारंटी नहीं है।
उत्पादन प्रणाली के बारे में भी यही कहा जा सकता है। यदि आपको नए डेटाबेस के साथ अपने एप्लिकेशन के नए इंस्टेंस को तेजी से स्पिन करने की आवश्यकता है—और सभी माइग्रेशन को क्रमिक रूप से चलाने में लंबा समय लगता है—डेटाबेस को structure.sql
से सेट करना फ़ाइल बहुत तेज होगी। हम निश्चिंत हो सकते हैं कि structure.sql
अन्य उदाहरणों की तरह ठीक उसी संरचना के साथ हमारा डेटाबेस तैयार करेगा।
बढ़ता दर्द
संक्षिप्त schema.rb
को प्रबंधित करना structure.sql
. वर्बोज़ को प्रबंधित करने की तुलना में एक टीम में फ़ाइल करना कहीं अधिक आसान काम है फ़ाइल।
structure.sql
में माइग्रेट करते समय सबसे बड़ी बढ़ती पीड़ाओं में से एक यह सुनिश्चित कर रहा है कि केवल आवश्यक परिवर्तन ही उस फ़ाइल के लिए प्रतिबद्ध हों, जिसे करना कभी-कभी मुश्किल हो सकता है।
मान लीजिए, उदाहरण के लिए, आप किसी की शाखा खींचते हैं और उस शाखा के लिए विशिष्ट माइग्रेशन चलाते हैं। आपका structure.sql
अब कुछ बदलाव होंगे। फिर आप अपनी शाखा में काम करने के लिए वापस जाते हैं और एक नया प्रवासन उत्पन्न करते हैं। आपका structure.sql
फ़ाइल में अब आपकी शाखा और दूसरी शाखा के परिवर्तन दोनों होंगे। इससे निपटने में थोड़ी परेशानी हो सकती है, और जब इन संघर्षों को प्रबंधित करने की बात आती है तो निस्संदेह सीखने की अवस्था थोड़ी होती है।
इस दृष्टिकोण का उपयोग करके, हम एक समझौता कर रहे हैं। हमें कुछ कोड जटिलता से पहले निपटना होगा जो हमें अपने डेटाबेस की उन्नत कार्यक्षमता को संरक्षित करने की अनुमति देता है। बदले में, हमें एक सरल स्कीमा प्रतिनिधित्व के साथ-साथ हमारी उंगलियों पर डेटाबेस की सारी शक्ति नहीं होने से भी निपटना होगा, उदा। अगर हम एक db:setup
. से बैकअप सेट करना चाहते हैं काम। मेरा मानना है कि किसी उत्पादन प्रणाली में भ्रष्ट/गलत डेटा को ठीक करने या आपके डेटाबेस द्वारा प्रदान की जाने वाली सभी उन्नत कार्यक्षमता का उपयोग करने में सक्षम न होने के बजाय संस्करण-नियंत्रण की थोड़ी सी परेशानी को झेलना सबसे अच्छा है।पी>
सामान्यतया, मैंने अपने structure.sql
. को सुनिश्चित करने के लिए दो रणनीतियों का उपयोग किया है फ़ाइल में केवल एक विशिष्ट शाखा में आवश्यक परिवर्तन होते हैं:
- एक बार जब आप किसी ऐसी शाखा पर काम कर लेते हैं जिसमें माइग्रेशन होता है, तो सुनिश्चित करें कि आप
rails db:rollback STEP=n
चलाते हैं। जहांn
उस शाखा में प्रवास की संख्या है। यह सुनिश्चित करेगा कि आपकी डेटाबेस संरचना अपनी मूल स्थिति में वापस आ जाए। - शाखा पर काम करने के बाद आप रोलबैक करना भूल सकते हैं। उस स्थिति में, एक नई शाखा पर काम करते समय, सुनिश्चित करें कि आप एक प्राचीन
structure.sql
खींचते हैं कोई भी नया माइग्रेशन बनाने से पहले मास्टर से फ़ाइल करें।
सामान्य तौर पर, आपका structure.sql
फ़ाइल में मास्टर में विलय होने से पहले केवल आपकी शाखा के लिए प्रासंगिक परिवर्तन होने चाहिए।
निष्कर्ष
आम तौर पर, जब रेल एप्लिकेशन छोटे होते हैं या डेटाबेस द्वारा प्रदान की जाने वाली कुछ अधिक उन्नत सुविधाओं की आवश्यकता नहीं होती है तो schema.rb
का उपयोग करना सुरक्षित होता है। , जो बहुत पठनीय, संक्षिप्त और प्रबंधित करने में आसान है।
हालाँकि, जैसे-जैसे कोई एप्लिकेशन आकार और जटिलता में बढ़ता है, डेटाबेस संरचना का एक सटीक प्रतिबिंब सार का होता है। यह एक टीम को सही बाधाओं, डेटाबेस मॉड्यूल, कार्यों और ऑपरेटरों को बनाए रखने की अनुमति देगा जो अन्यथा संभव नहीं होगा। एक सुव्यवस्थित structure.sql
. के साथ रेल का उपयोग करना सीखना फ़ाइल एक बढ़त प्रदान करेगी कि आसान schema.rb
बस नहीं कर सकता।
पी.एस. यदि आप रूबी मैजिक की पोस्ट प्रेस से छूटते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर की सदस्यता लें और एक भी पोस्ट मिस न करें!