आज की पोस्ट में, हम रेल माइग्रेशन के बारे में गहराई से जानेंगे। हम माइग्रेशन को अलग-अलग हिस्सों में बांटेंगे, और इस प्रक्रिया में, प्रभावी माइग्रेशन लिखना सीखेंगे। हम सीखेंगे कि एकाधिक डेटाबेस के लिए माइग्रेशन कैसे लिखना है, साथ ही असफल माइग्रेशन और रोलबैक करने की तकनीकों को कैसे संभालना है।
पूरी पोस्ट को समझने के लिए, आपको डेटाबेस और रेल की बुनियादी समझ होनी चाहिए।
माइग्रेशन 101
रेल में प्रवासन हमें किसी एप्लिकेशन के जीवनकाल में डेटाबेस विकसित करने की अनुमति देता है। माइग्रेशन हमें एक सुंदर डीएसएल प्रदान करके डेटाबेस की स्थिति को बदलने के लिए सादा रूबी कोड लिखने की अनुमति देता है। हमें डेटाबेस-विशिष्ट SQL लिखने की आवश्यकता नहीं है क्योंकि माइग्रेशन डेटाबेस में हेरफेर करने के लिए एब्स्ट्रैक्शन प्रदान करते हैं और दृश्य के पीछे DSL को डेटाबेस-विशिष्ट SQL क्वेरी में परिवर्तित करने के बारीक-बारीक विवरणों का ध्यान रखते हैं। माइग्रेशन भी हमारे रास्ते से हट जाते हैं और जरूरत पड़ने पर डेटाबेस पर रॉ SQL को निष्पादित करने के तरीके प्रदान करते हैं।
बीस हजार लीग एक रेल डेटाबेस माइग्रेशन में
हम माइग्रेशन का उपयोग करके टेबल बना सकते हैं, कॉलम जोड़ या हटा सकते हैं और कॉलम पर इंडेक्स जोड़ सकते हैं।
<ब्लॉकक्वॉट>
प्रत्येक रेल ऐप की एक विशेष निर्देशिका होती है—db/migrate
—जहां सभी माइग्रेशन संग्रहीत हैं।
आइए एक ऐसे माइग्रेशन से शुरू करें जो टेबल बनाता है events
हमारे डेटाबेस में।
$ rails g migration CreateEvents category:string
यह आदेश एक टाइमस्टैम्प फ़ाइल उत्पन्न करता है 20200405103635_create_events.rb
db/migrate
. में निर्देशिका। फ़ाइल की सामग्री इस प्रकार है।
class CreateEvents < ActiveRecord::Migration[6.0]
def change
create_table :events do |t|
t.string :category
t.timestamps
end
end
end
आइए इस माइग्रेशन फ़ाइल को तोड़ते हैं।
- रेल द्वारा जनरेट की जाने वाली प्रत्येक माइग्रेशन फ़ाइल में एक टाइमस्टैम्प होता है जो फ़ाइल नाम में मौजूद होता है। यह टाइमस्टैम्प महत्वपूर्ण है और रेल द्वारा यह पुष्टि करने के लिए उपयोग किया जाता है कि माइग्रेशन चला है या नहीं, जैसा कि हम बाद में देखेंगे।
- माइग्रेशन में एक वर्ग है जो
ActiveRecord::Migration[6.0]
से इनहेरिट करता है . जैसा कि मैं रेल 6 का उपयोग कर रहा हूं, माइग्रेशन सुपरक्लास में[6.0]
. है . अगर मैं रेल 5.2 का उपयोग कर रहा था, तो सुपरक्लासActiveRecord::Migration[5.2]
होगा . बाद में, हम चर्चा करेंगे कि रेल संस्करण सुपरक्लास नाम का हिस्सा क्यों है। - माइग्रेशन की एक विधि होती है
change
जिसमें डीएसएल कोड होता है जो डेटाबेस में हेरफेर करता है। इस मामले में,change
विधि एकevents
बना रही है एक कॉलम के साथ तालिकाcategory
प्रकार काstring
। - माइग्रेशन कोड का उपयोग करता है
t.timestamps
टाइमस्टैम्प जोड़ने के लिएcreated_at
औरupdated_at
events
. के लिए टेबल.
जब यह माइग्रेशन rails db:migrate
. का उपयोग करके चलाया जाता है कमांड, यह एक events
बनाएगा category
. के साथ तालिका प्रकार का स्तंभ string
और टाइमस्टैम्प कॉलम created_at
और updated_at
।
डेटाबेस के आधार पर वास्तविक डेटाबेस कॉलम प्रकार वर्चर या टेक्स्ट होगा।
माइग्रेशन टाइमस्टैम्प और स्कीमा_माइग्रेशन टेबल का महत्व
हर बार rails g migration
. का उपयोग करके माइग्रेशन जेनरेट किया जाता है कमांड, रेल एक अद्वितीय टाइमस्टैम्प के साथ माइग्रेशन फ़ाइल उत्पन्न करता है। टाइमस्टैम्प YYYYMMDDHHMMSS
. के प्रारूप में है .जब भी कोई माइग्रेशन चलाया जाता है, रेल माइग्रेशन टाइमस्टैम्प को आंतरिक तालिका schema_migrations
में सम्मिलित करता है . जब हम अपना पहला माइग्रेशन चलाते हैं तो यह तालिका रेल द्वारा बनाई जाती है। तालिका में केवल कॉलम version
. है , जो इसकी प्राथमिक कुंजी भी है। यह schema_migrations
. की संरचना है टेबल।
CREATE TABLE IF NOT EXISTS "schema_migrations" ("version" varchar NOT NULL PRIMARY KEY);
अब जबकि हमने events
. बनाने के लिए माइग्रेशन चला लिया है तालिका, देखते हैं कि रेल ने इस माइग्रेशन के एटिमस्टैम्प को schema_migrations
में संग्रहीत किया है या नहीं टेबल।
sqlite> select * from schema_migrations;
20200405103635
यदि हम फिर से माइग्रेशन चलाते हैं, तो रेल पहले जांच करेगी कि schema_migrations
में कोई प्रविष्टि मौजूद है या नहीं माइग्रेशन फ़ाइल के टाइमस्टैम्प के साथ तालिका, और ऐसी कोई प्रविष्टि न होने पर ही इसे निष्पादित करें। यह सुनिश्चित करता है कि हम समय के साथ डेटाबेस में क्रमिक रूप से परिवर्तन जोड़ सकते हैं और माइग्रेशन डेटाबेस पर केवल एक बार चलेगा।
डेटाबेस स्कीमा
जैसे-जैसे हम अधिक से अधिक माइग्रेशन चलाते हैं, डेटाबेस स्कीमा विकसित होता रहता है। रेल नवीनतम डेटाबेस स्कीमा को db/schema.rb
. फ़ाइल में संग्रहीत करता है . यह फ़ाइल एप्लिकेशन के पूरे जीवन में आपके डेटाबेस पर सभी माइग्रेशन का रूबी प्रतिनिधित्व है। इस फ़ाइल के कारण, हमें पुरानी माइग्रेशन फ़ाइलों को कोडबेस में रखने की आवश्यकता नहीं है। रेल dump
को कार्य प्रदान करता है डेटाबेस से नवीनतम स्कीमा schema.rb
. में और load
schema.rb
. से डेटाबेस में स्कीमा . इसलिए पुराने माइग्रेशन को कोडबेस से सुरक्षित रूप से हटाया जा सकता है। हर बार जब हम एप्लिकेशन सेट करते हैं तो प्रत्येक माइग्रेशन को चलाने की तुलना में डेटाबेस में स्कीमा लोड करना भी तेज़ होता है।
रेल एसक्यूएल प्रारूप में डेटाबेस स्कीमा को स्टोर करने का एक तरीका भी प्रदान करता है। दो प्रारूपों की तुलना करने के लिए हमारे पास पहले से ही एक लेख है। आप इसके बारे में यहाँ और अधिक पढ़ सकते हैं।
प्रवास में रेल संस्करण
हमारे द्वारा उत्पन्न प्रत्येक माइग्रेशन में सुपरक्लास के हिस्से के रूप में रेल संस्करण होता है। इसलिए रेल 6 ऐप द्वारा उत्पन्न माइग्रेशन में सुपरक्लास होता है ActiveRecord::Migration[6.0]
जबकि रेल 5.2 ऐप द्वारा उत्पन्न माइग्रेशन में सुपरक्लास ActiveRecord::Migration[5.2]
है . यदि आपके पास रेल 4.2 या उससे नीचे का पुराना ऐप है, तो आप देखेंगे कि सुपरक्लास में कोई संस्करण नहीं है। सुपरक्लास सिर्फ ActiveRecord::Migration
है ।
रेल संस्करण को रेल 5 में माइग्रेशन सुपरक्लास में जोड़ा गया था। यह मूल रूप से सुनिश्चित करता है कि माइग्रेशनएपीआई रेल के पुराने संस्करणों द्वारा उत्पन्न माइग्रेशन को तोड़े बिना समय के साथ विकसित हो सकता है।
आइए एक events
. बनाने के लिए उसी माइग्रेशन को देखकर इस पर गहराई से विचार करें एक रेल 4.2 ऐप में तालिका।
class CreateEvents < ActiveRecord::Migration
def change
create_table :events do |t|
t.string :category
t.timestamps null: false
end
end
end
अगर हम events
. के स्कीमा को देखें तो एक रेल 6 माइग्रेशन द्वारा उत्पन्न तालिका, हम देख सकते हैं कि NOT NULL
टाइमस्टैम्प कॉलम के लिए बाधा मौजूद है।
sqlite> .schema events
CREATE TABLE IF NOT EXISTS "events" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "category" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
ऐसा इसलिए है, क्योंकि रेल 5 से शुरू होकर, माइग्रेशन एपीआई स्वचालित रूप से एक NOT NULL
adds जोड़ता है माइग्रेशन फ़ाइल में स्पष्ट रूप से जोड़ने की आवश्यकता के बिना टाइमस्टैम्प कॉलम के लिए बाधा। सुपरक्लास नाम में रेल संस्करण यह सुनिश्चित करता है कि माइग्रेशन रेल संस्करण के माइग्रेशन एपीआई का उपयोग करता है जिसके लिए माइग्रेशन उत्पन्न हुआ था। यह रेल को पुराने माइग्रेशन के साथ पिछड़ा संगतता बनाए रखने की अनुमति देता है, साथ ही साथ माइग्रेशन API को विकसित करता है।
डेटाबेस स्कीमा बदलना
change
प्रवासन में विधि प्राथमिक विधि है। जब कोई माइग्रेशन चलाया जाता है, तो वह change
को कॉल करता है विधि और उसके अंदर कोड निष्पादित करता है।
साथ में create_table
, रेल एक और शक्तिशाली तरीका भी प्रदान करता है—change_table
जैसा कि नाम से पता चलता है, इसका उपयोग मौजूदा तालिका के स्कीमा को बदलने के लिए किया जाता है।
def change
change_table :events do |t|
t.remove :category
t.string :event_type
t.boolean :active, default: false
end
end
यह माइग्रेशन category
को हटा देगा events
. से कॉलम तालिका में, एक नया स्ट्रिंग कॉलम जोड़ें events_type
और एक नया बूलियन कॉलम active
false
. के डिफ़ॉल्ट मान के साथ ।
रेल कई अन्य सहायक विधियाँ भी प्रदान करता है जिनका उपयोग प्रवास के अंदर किया जा सकता है जैसे:
change_column
add_index
remove_index
rename_table
और भी कई। परिवर्तन के साथ उपयोग की जा सकने वाली सभी विधियों को यहां पाया जा सकता है
टाइमस्टैम्प
हमने देखा कि t.timestamps
रेल द्वारा माइग्रेशन में जोड़ा गया था और इसने कॉलम जोड़ेcreated_at
और updated_at
events
. के लिए मेज़। इन विशेष स्तंभों का उपयोग रेलस्टो द्वारा रिकॉर्ड बनाए जाने और अद्यतन किए जाने पर नज़र रखने के लिए किया जाता है। जब कोई रिकॉर्ड बनाया जाता है तो रेल इन स्तंभों में मान जोड़ता है और रिकॉर्ड अपडेट होने पर उन्हें अपडेट करना सुनिश्चित करता है। ये कॉलम डेटाबेस रिकॉर्ड के जीवनकाल को ट्रैक करने में हमारी मदद करते हैं।
updated_at
जब हम updated_all
. निष्पादित करते हैं तो कॉलम अपडेट नहीं होता है रेल से विधि।
विफलताओं को संभालना
माइग्रेशन बुलेटप्रूफ नहीं हैं। वे असफल हो सकते हैं। इसका कारण गलत सिंटैक्स या अमान्य डेटाबेस क्वेरी हो सकता है। कारण जो भी हो, हमें विफलता को संभालना होगा और उससे उबरना होगा ताकि डेटाबेस असंगत स्थिति में न जाए। लेन-देन के अंदर प्रत्येक माइग्रेशन चलाकर रेल इस समस्या को हल करती है। यदि माइग्रेशन विफल हो जाता है, तो लेन-देन वापस ले लिया जाता है। यह सुनिश्चित करता है कि डेटाबेस असंगत स्थिति में नहीं जाता है।
<ब्लॉकक्वॉट>यह केवल उन डेटाबेस के लिए किया जाता है जो डेटाबेस स्कीमा को अपडेट करने के लिए लेनदेन का समर्थन करते हैं। उन्हें डेटा डेफिनिशन लैंग्वेज (डीडीएल) लेनदेन के रूप में जाना जाता है। MySQL और PostgreSQL दोनों ही DDL लेनदेन का समर्थन करते हैं।
कभी-कभी, हम लेन-देन के अंदर कुछ माइग्रेशन निष्पादित नहीं करना चाहते हैं। PostgreSQL में समवर्ती अनुक्रमणिका जोड़ते समय एक सरल उदाहरण है। इस तरह के माइग्रेशन को डीडीएल लेनदेन के अंदर निष्पादित नहीं किया जा सकता है क्योंकि PostgreSQL टेबल पर ताले प्राप्त किए बिना इंडेक्स जोड़ने की कोशिश करता है ताकि हम डेटाबेस को नीचे ले जाए बिना लाइव प्रोडक्शन डेटाबेस पर इंडेक्स जोड़ सकें। रेल disable_ddl_transactions!
के रूप में माइग्रेशन के अंदर लेनदेन से ऑप्ट-आउट करने का एक तरीका प्रदान करती है। ।
def change
disable_ddl_transactions!
add_index :events, :user_id, algorithm: :concurrently
यह किसी लेन-देन के अंदर माइग्रेशन नहीं चलाएगा। यदि ऐसा प्रवास विफल हो जाता है, तो हमें इसे स्वयं पुनर्प्राप्त करने की आवश्यकता है। इस मामले में, हम या तो REINDEX
. कर सकते हैं या अनुक्रमणिका निकालें और इसे फिर से जोड़ने का प्रयास करें।
प्रतिवर्ती माइग्रेशन
रेल हमें निम्न आदेश के साथ डेटाबेस में परिवर्तनों को रोलबैक करने की अनुमति देता है।
rails db:rollback
यह आदेश डेटाबेस पर चलाए गए अंतिम माइग्रेशन को पूर्ववत करता है। अगर माइग्रेशन ने एक कॉलम जोड़ा हैevent_type
फिर रोलबैक उस कॉलम को हटा देगा। अगर माइग्रेशन ने एक इंडेक्स जोड़ा है, तो रोलबैक उस इंडेक्स को हटा देगा।
पिछले माइग्रेशन को वापस रोल करने और उसे चलाने के लिए एक कमांड भी है। यह है rails db:redo
।
अधिकांश माइग्रेशन को उलटने का तरीका जानने के लिए रेल काफी स्मार्ट है। लेकिन हम रेलसन को up
. प्रदान करके माइग्रेशन को वापस करने के संकेत भी दे सकते हैं और down
change
. का उपयोग करने के बजाय विधियों method.The up
विधि का उपयोग तब किया जाएगा जब माइग्रेशन चलाया जाता है जबकि down
विधि का उपयोग तब किया जाएगा जब माइग्रेशन वापस ले लिया जाए।
def up
change_table :events do |t|
t.change :price, :string
end
end
def down
change_table :events do |t|
t.change :price, :integer
end
end
इस उदाहरण में, हम price
बदल रहे हैं events
. का कॉलम integer
. से करने के लिए string
. हम निर्दिष्ट करते हैं कि इसे down
. में कैसे वापस लाया जाना चाहिए विधि।
इसी माइग्रेशन को change
. का उपयोग करके भी लिखा जा सकता है विधि।
def change
reversible do |direction|
change_table :events do |t|
direction.up { t.change :price, :string }
direction.down { t.change :price, :integer }
end
end
end
रेल्स revert
. का उपयोग करके पिछले माइग्रेशन को पूरी तरह से वापस करने का एक तरीका भी प्रदान करता है विधि।
def change
revert CreateEvents
create_table :events do
...
end
end
revert
विधि आंशिक रूप से माइग्रेशन को वापस करने के लिए ब्लॉक को भी स्वीकार करती है।
def change
revert do
reversible do |direction|
change_table :events do |t|
direction.up { t.remove :event_type }
direction.down { t.string :event_type }
end
end
end
end
इसे कच्चा निष्पादित करना
कभी-कभी, हम माइग्रेशन के अंदर जटिल SQL निष्पादित करना चाहते हैं। ऐसे मामलों में, हम विशिष्ट माइग्रेशन DSL को भूल सकते हैं और इसके बजाय कच्चे SQL को निम्नानुसार निष्पादित कर सकते हैं।
def change
execute <<-SQL
....
SQL
end
एकाधिक डेटाबेस और माइग्रेशन
रेल 6 ने एक ही रेल एप्लिकेशन के भीतर कई डेटाबेस का उपयोग करने के लिए समर्थन जोड़ा। यदि हम कई डेटाबेस का उपयोग करना चाहते हैं, तो हम उन्हें database.yml
में कॉन्फ़िगर करते हैं। फ़ाइल।
development:
primary:
<<: *default
database: db/development.sqlite3
analytics:
adapter: sqlite3
database: db/analytics_dev.sqlite3
यह कॉन्फ़िगरेशन रेल को बताता है कि हम दो डेटाबेस का उपयोग करना चाहते हैं-primary
और analytics
.जैसा कि हमने पहले देखा, माइग्रेशन db/migrate
. में स्टोर हो जाते हैं डिफ़ॉल्ट रूप से निर्देशिका। लेकिन इस मामले में, हम एक ही निर्देशिका के अंदर दोनों डेटाबेस के माइग्रेशन को नहीं जोड़ सकते। हम analytics
. के माइग्रेशन नहीं चलाना चाहते हैं primary
. पर डेटाबेस डेटाबेस और इसके विपरीत। यदि हम एकाधिक डेटाबेस का उपयोग कर रहे हैं, तो दूसरे डेटाबेस के लिए माइग्रेशन संग्रहीत करने के लिए पथ प्रदान करने की आवश्यकता होगी। यह एक migrations_paths
. प्रदान करके किया जा सकता है database.yml
. में ।
development:
primary:
<<: *default
database: db/development.sqlite3
analytics:
adapter: sqlite3
database: db/analytics_dev.sqlite3
migrations_paths: db/analytics_migrate
फिर हम analytics
. के लिए माइग्रेशन बना सकते हैं डेटाबेस इस प्रकार है।
rails generate migration AddExperiments rule:string active:boolean --db=analytics
इससे db/analytics_migrate
. के अंदर माइग्रेशन बन जाएगा , और हम इसे निम्नानुसार चला सकते हैं।
rails db:migrate --db=analytics
अगर हम केवल rails db:migrate
चलाते हैं , यह सभी डेटाबेस के लिए माइग्रेशन निष्पादित करेगा।
analytics
डेटाबेस का अपना schema_migrations
होगा यह ट्रैक रखने के लिए कि कौन से माइग्रेशन चल रहे हैं और कौन से नहीं हैं।
तैनाती के दौरान माइग्रेशन चलाना
चूंकि माइग्रेशन डेटाबेस की स्थिति को बदल सकते हैं, और हमारा कोड उन परिवर्तनों पर निर्भर हो सकता है, इसलिए यह अत्यंत महत्वपूर्ण है कि नए कोड लागू होने से पहले माइग्रेशन चलाए जाएं।
Heroku आधारित परिनियोजन में, माइग्रेशन release
. में चलाया जा सकता है Procfile
का चरण ।
# Profile
web: bin/puma -C config/puma.rb
release: bundle exec rake db:migrate
यह सुनिश्चित करता है कि ऐप डायनोस के पुनरारंभ होने से पहले माइग्रेशन चलाए जाते हैं।
Capistrano आधारित परिनियोजन में, सर्वर के पुनरारंभ होने से पहले माइग्रेशन चलना चाहिए।
डॉकटर आधारित परिनियोजन में, हम ऐप के पुनरारंभ होने से पहले माइग्रेशन चलाने के लिए एक साइडकार कंटेनर चला सकते हैं। यह बहुत महत्वपूर्ण है क्योंकि अन्यथा, नए कंटेनर असंगत स्थिति में जा सकते हैं यदि वे उस नए कोड के लिए डेटाबेस परिवर्तन लागू करने से पहले नए कोड का उपयोग करना शुरू करते हैं।
निष्कर्ष
इस पोस्ट में, हमने रेल में डेटाबेस माइग्रेशन लिखने के विभिन्न पहलुओं को देखा। हमने यह भी देखा कि माइग्रेशन क्या होता है और साथ ही विफलताओं से कैसे निपटा जाए और जरूरत पड़ने पर माइग्रेशन को वापस कैसे लाया जाए। रेल 6 हमें कई डेटाबेस का उपयोग करने की अनुमति देता है और प्रत्येक के लिए माइग्रेशन को अलग से जोड़ने की आवश्यकता होती है। अंत में, हमने संक्षेप में देखा कि परिनियोजन के दौरान माइग्रेशन को कैसे चलाया जाए ताकि किसी भी नए कोड का उपयोग शुरू करने से पहले डेटाबेस परिवर्तन ठीक से लागू हो जाएं।
पी.एस. यदि आप रूबी मैजिक की पोस्ट प्रेस से छूटते ही पढ़ना चाहते हैं, तो हमारे रूबी मैजिक न्यूजलेटर की सदस्यता लें और एक भी पोस्ट मिस न करें!