আজকের পোস্টে, আমরা structure.sql
ব্যবহারের উল্লেখযোগ্য পার্থক্য এবং সুবিধাগুলি কভার করব বনাম ডিফল্ট schema.rb
আপনার রুবি অন রেল অ্যাপ্লিকেশনে স্কিমা ফরম্যাট। একটি ডেটা-চালিত বিশ্বে, কীভাবে আপনার ডেটাবেসের সমৃদ্ধ বৈশিষ্ট্যগুলিকে কাজে লাগাতে হয় তা জেনে একটি সফল এবং অসফল এন্টারপ্রাইজের মধ্যে পার্থক্য করতে পারে৷
দুটি ফরম্যাটের মধ্যে প্রধান পার্থক্য তুলে ধরার পর, আমরা কিভাবে structure.sql
-এ স্যুইচ করতে হয় তার রূপরেখা দেব। এবং প্রদর্শন করুন কিভাবে এটি ডেটা অখণ্ডতা এবং সেইসাথে ডেটাবেস কার্যকারিতা নিশ্চিত করতে সাহায্য করতে পারে যা অন্যথায় আপনি সংরক্ষণ করতে পারবেন না৷
পোস্টে, আমি একটি Rails অ্যাপের উদাহরণ দেব যা 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
ফাইলটি দেখতে পাবেন . ভয়লা ! আপনি যে ডাটাবেস ব্যবহার করছেন তার জন্য নির্দিষ্ট টুল ব্যবহার করে রেল ডাটাবেস কাঠামো ডাম্প করবে (PostgreSQL-এর ক্ষেত্রে, সেই টুলটি হল 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
আপনি যদি 'ড্যান' নামের একজন ব্যবহারকারী তৈরি করার চেষ্টা করেন, তাহলে যাচাইকরণ চলাকালীন আপনি একটি ত্রুটি দেখতে পাবেন:
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 একটি আশীর্বাদের পাশাপাশি একটি অভিশাপও হতে পারে—যদিও এটিতে একটি অত্যন্ত পরিষ্কার এবং স্বাভাবিক DSL রয়েছে যা এটির সাথে কাজ করাকে আনন্দ দেয়, মডেল-স্তরের বৈধতা প্রয়োগ করার সময় এটি প্রায়শই অত্যধিক অনুমোদনযোগ্য। সমাধান, আপনি ইতিমধ্যেই জানেন, ডাটাবেস-স্তরের সীমাবদ্ধতা যোগ করা।
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
উভয়ই কার্যকর করা যেতে পারে এবং 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
চালাতেন একটি structure.sql
থাকা ফাইল, আপনার ডাটাবেসের কাঠামো উপরের সীমাবদ্ধতা ধারণ করবে। 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
সহজভাবে পারে না।
পি.এস. আপনি যদি রুবি ম্যাজিক পোস্টগুলি প্রেস থেকে বের হওয়ার সাথে সাথে পড়তে চান তবে আমাদের রুবি ম্যাজিক নিউজলেটারে সাবস্ক্রাইব করুন এবং একটি পোস্টও মিস করবেন না!