في الدرس السابق ألقينا نظرة عامة على تهجير Active Record وكيفية إنشائه وسنتابع في هذا الدرس تعلّم كيفية كتابة أوامره عبر صنع الجداول وتعديلها وغيرها.
3 كتابة أوامر التهجير
بمجرد استخدامك للمولدات لتوليد التهجير، فسيتحتم عليك البدء بالعمل الحقيقي و كتابة أوامر التهجير.
3.1 صُنع الجداول
إن دالة create_tables
هي الأساسية لصنع الجداول، و لكن في مُعظم الأوقات ستقوم المولدات بإنتاج تلك الجداول كما رأينا في الأمثلة السابقة. مثال على صُنع جدول
create_table :products do |t| t.string :name end
وهذا سوف يصنع جدول يُسمى products يحتوي على عامود نصي يُسمى name (وعامود مُفتاح رئيسي يُسمى id يتولد تلقائيًا كما ناقشنا من قبل) و تلقائيًا، ستنتج دالة create_table
ستصنع عامود مُفتاح رئيسي id. يُمكنك تغيير إسم هذا المُفتاح باستخدام أمر primary_key:
(ولا تنسَ أن تقوم بهذا التغيير في بقية النماذج models)، كما يُمكنك إلغاء وجود ذلك المُفتاح إن لم تحتاجه بإستخدام أمر id: false
. أما إذا أردت تعديل تخطي بعض الخيارات الأخرى لقاعدة البيانات، فيُمكنك استخدام سطور SQL في خيار options:
وعلى سبيل المثال:
create_table :products, options: "ENGINE=BLACKHOLE" do |t| t.string :name, null: false end
وهذا الكود سوف يُضيف ENGINE = BLACKHOLE
إلى سطور SQL المسؤولة عن صُنع الجداول ( وفي حالة استعمال MySQL أو MariaDB، فإن الكود المُستخدم هو ENGINE = InnoDB
). يُمكنك تعدي خيار comment:
باستخدام أي وصف للجدول مُخزن في قاعدة البيانات نفسها و سيتم ظهور هذا الوصف أدوات إدارة قاعدة البيانات، مثل MySQL Workbench أو PgAdmin III. كما أنه من المُفضل لتوضيح التعليقات comments في التهجيرات المُستخدمة بتطبيقات قواعد البيانات الكبيرة. حيث سُتساعد من يقرأ قاعدة البيانات لفهم نماذج البيانات و عمل التوثيقات اللازمة لقاعدة البيانات.
3.2 صُنع الجداول المُدمجة
إن دالة التهجير creat_join_table
تقوم بصُنع جداول مُدمجة (HABTM-has and belongs to many) و التي كما عرفناها سابقًا عبارة عن عدة عواميد من جدول واحد أو جداول مُختلفة. مثال:
create_join_table :products, :categories
و هذا سوف يصنع جدول categories_products
يحتوي على عامودين يُسميان category_id
و product_id
. وهذه العواميد تلقائيًا تُعطي قيمة false
للأمر null:
و يُمكن تخطي هذا الأمر بالتعديل على الخيار column_options:
، مثال:
create_join_table :products, :categories, column_options: { null: true }
إسم الجدول المُدمج سيتكون من إسم العواميد المكونة له طبقًا لترتيبها الأبجدي، و لتغير ذلك يُمكنك إستخدام قواعد التسمية المُستخدمة في المقال السابق و بدالة table_name:
، مثال:
create_join_table :products, :categories, table_name: :categorization
مما سينتج عن الكود السابق جدول يُسمى categorization. كما أن دالة create_join_table
يُمكنها إضافة الفهارس و العواميد الإضافية (و لا يتم عمل ذلك بشكل تلقائي إذ يجب عليك تحديد الفهارس أو العواميد الإضافية) مثال:
create_join_table :products, :categories do |t|
t.index :product_id
t.index :category_id
end
3.3 تغيير الجداول
إن دالة تغيير الجداول change_table
مُشابهة لدالة صُنعها create_table
عدا أن الثانية تُستخدم لتغير جداول موجودة مُسبقًا. و تعمل بنفس الطريقة و لكنك لن تحتاج إعادة تعريف كُل شيئ لأنه سيأخُذها من الجدول المُتغير منه. مثال على ذلك:
change_table :products do |t|
t.remove :description, :name
t.string :part_number
t.index :part_number
t.rename :upccode, :upc_code
end
الكود السابق سوف يحذف العواميد description
و columns
. و سيصنع عامود نصي part_number
وسيضيف فهرس إليه، و سيقوم أيضًا بإعادة تسمية عامود upccode
.
3.4 تغيير الأعمدة
توفر Rails أمر التهجير change_column
و الذي يؤدي دور الأوامر remove_column
و add_column
.
change_column :products, :part_number, :text
الكود أعلاه سيُغير نوع العامود part_number
في الجدول products ليُصبح حقل نصوص texts. لاحظ أن الدالة change_column
لا يُمكن عكسها. وبجانب دالة change_column
يوجد دوال change_column_null
و change_column_default
التي تُستخدم تحديدًا لتغيير القيم الإفتراضية default values
للعامود.
change_column_null :products, :name, false
change_column_default :products, :approved, from: true, to: false
الكود أعلاه سيقوم بتغيير الحقل name:
في جدول products
ليُصبح من نوع NOT NULL
و القيمة الإفتراضية لحقل approved:
من true
إلى false
.
اقتباسمُلاخظة: يُوجد طريقة أخرى لكتابة أمر التهجير
change_column_default
و هيchange_column_default :products, :approved, false
و لكن هذه الطريقة لا يُمكن عكسهاirreversible
عكس المُستخدمة في الكود أعلاه.
3.5 مُعدلات الأعمدة
إن مُعدلات الأعمدة Column Modifiers يُمكن أن تُطبق عند صُنع أو تغيير العواميد:
-
limit
: يقوم بتحديد أقصى مساحة للحقول من الأنواعstring/text/binary/integer
-
Precision :
يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد قبل العلامة العشرية -
Scale
: يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد بعد العلامة العشرية -
Polymorphic
: يُضيف عامودtype
إلى رابطةbelong_to
-
Null
: تسمح بإستخدام قيمةNULL
أو عدم إستخدامها بالعامود. -
Default
: يُتيح لك بتعيين قيمة إفتراضية بالعامود. مع مُلاحظة أنه عند إستخدامك قيمة ديناميكية (مثل التاريخ، فإنه سيتم تعيين القيمة الإفتراضية للتاريخ الذي تم صُنع التهجير عنده. -
Index
: يُضيف فهرس للعامود -
Comment
: يُضيف تعليق للعامود
بعض المحولات adapters
تدعم بعض الخيارات الإضافية: يُمكنك رؤية التوثيقات الخاصة بتلك المحولات لمعرفة المزيد عن هذا الأمر.
اقتباس**لاحظ أنه أمري
null
وsupport
لا يُمكن تحديدهم بإستخدام واجهة الأوامر Command Line
3.6 المفاتيح الأجنبية
على الرغم من عدم إضطرارك لإضافة المفاتيح الأجنبية Foreign Keys إلا أنه يُمكنك فعل ذلك لضمان السلامة المرجعية لقاعدة البيانات.
add_foreign_key :articles, :authors
هذا سوف يُضيف مفتاح أجنبي جديد إلى عامود author_id
في جدول articles
. والمفتاح سيرمز إلى عامود id
في جدول authors
. أما إذا كانت أسماء الأعمدة لا يُمكن إشتقاقها من أسماء الجداول، فيُمكنك إستخدام الأوامر column:
و primary_key:
. إن Rails أيضًا ستقوم بتوليد إسم إفتراضي لكُل مُفتاح أجنبي، سيبدأ بـ fk_rails_
ثُم سيُتبع بعشرة حروف التي ستتولد تلقائيًا من أمر from_table
و column
. و يُمكنك أيضًا إستخدام name:
لتعيين إسم مُختلف إذا أردت.
اقتباس**ملحوظة: إن Active Record يدعم عامود واحد من المفاتيح الأجنبية foreign keys. عدا ذلك يُمكنك إستخدام ملف
excute.sql
أوstructre.sql
لإستخدام العديد منها.
حذف المفاتيح الأجنبية لهو أمر سهل أيضًا:
# let Active Record figure out the column name
remove_foreign_key :accounts, :branches
# remove foreign key for a specific column
remove_foreign_key :accounts, column: :owner_id
# remove foreign key by name
remove_foreign_key :accounts, name: :special_fk_name
3.7 إستخدام دالة التغيير change
إن دالة التغيير change
هي الطريقة الأساسية لكتابة أوامر التهجير (حيث كما علمنا فإن التهجير هو عبارة عن تغيير في الأساس). و في أغلب الحالات، فإن Active Record يُمكنه عكس تلك التهجيرات. حاليًا، يُمكنك إستخدام دالة التغيير على الدوال الآتية:
-
add_column
-
add_foreign_key
-
add_index
-
add_reference
-
add_timestamps
-
change_column_default (must supply a :from and :to option)
-
change_column_null
-
create_join_table
-
create_table
-
disable_extension
-
drop_join_table
-
drop_table (must supply a block)
-
enable_extension
-
remove_column (must supply a type)
-
remove_foreign_key (must supply a second table)
-
remove_index
-
remove_reference
-
remove_timestamps
-
rename_column
-
rename_index
-
rename_table
دالة change_table
يُمكن عكسها في حالة أن الجدول لا يقوم بإستدعاء دالة change
أو change_default
أو remove
. ودالة remove_column
أيضًا يُمكن عكسها إذا قُمت بتوفير نوع العامود كعامل ثالث موفرًا أيضًا باقي خيارات العامود. وبدون ذلك فإن Rails لن تتمكن من عمل العامود عند إستخدام الأوامر العكسية:
remove_column :posts, :slug, :string, null: false, default: '', index: true
أما إذا أُضطررت لإستعمال دوال أخرى فعليك إستعمال أمر reversible
أو كتابة أوامر up
و down
بدلًا من إستعمال دالة change
.
3.9 إستعمال أمر العكس reversible
إن التهجيرات المُعقدة تتطلب مُعالجة لا يستطيع Active Record عكسها. لذلك يُمكنك إستخدام أمر reversible
لتحديد ماذا يحدث عند تشغيل التهجير و ماذا يحدث عند عكسه، مثال:
class ExampleMigration < ActiveRecord::Migration[5.0]
def change
create_table :distributors do |t|
t.string :zipcode
end
reversible do |dir|
dir.up do
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5) NO INHERIT;
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
end
end
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
end
إن إستعمال دالة reversible
سوف تتأكد من تنفيذ excute
سطور الكود في الترتيب الصحيح. ففي المثال السابق، سيتم عكس التهجير بالترتيب، فسيتم تشغيل البلوك down
بعد حذف عامود home_page_url
و قبل إضافة جدول distributors
. في بعض الأحيان، لن يُمكن عكس عملية التهجير. لأنه –وعلى سبيل المثال- قد تؤدي إلى تدمير بعض البيانات. في هذه الحالات يُمكنك إستخدام أمر ActiveRecord::IrreversibleMigration
في البلوك down
. و إذا حاول أحد عكس التهجير فإن رسالة خطأ error message
ستُخبره بأن هذا الأمر غير مُمكن.
3.10 إستعمال دوال up/down
يُمكنك إستعمال الأسلوب القديم للتهجير بدوال up
و down
بدلًا من إستعمال دالة change
. فإن دالة up
يجب أن تصف فيها التغيرات التي تريد عملها في الإسكيما. و دالة down
ستقوم بعكس التغيير الذي قامت به دالة up
. بإختصار، فإنك إذا قُمت بتطبيق دالة up
ثُم بعد ذلك دالة down
فيجب ألا يحدث تغيير على قاعدة البيانات. و من المُرجح أن تكون التغييرات التي ستقوم بها دالة up
يُمكن عكسها بسهولة. المثال السابق ذكره في قسم (3.9 أمر العكس) سيؤدي وظيفته هذا المثال:
class ExampleMigration < ActiveRecord::Migration[5.0]
def up
create_table :distributors do |t|
t.string :zipcode
end
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5);
SQL
add_column :users, :home_page_url, :string
rename_column :users, :email, :email_address
end
def down
rename_column :users, :email_address, :email
remove_column :users, :home_page_url
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
drop_table :distributors
end
end
في بعض الأحيان، لن يُمكن عكس عملية التهجير. لأنه –وعلى سبيل المثال- قد تؤدي إلى تدمير بعض البيانات. في هذه الحالات يُمكنك إستخدام أمر ActiveRecord::IrreversibleMigration
في البلوك down
. و إذا حاول أحد عكس التهجير فإن رسالة خطأ error message
ستُخبره بأن هذا الأمر غير مُمكن.
3.11 عكس تهجيرات سابقة
يُمكنك إستعمال دالة revert
في Active Record لعكس التهجيرات السابقة:
require_relative '20121212123456_example_migration'
class FixupExampleMigration < ActiveRecord::Migration[5.0]
def change
revert ExampleMigration
create_table(:apples) do |t|
t.string :variety
end
end
end
دالة reverse
أيضًا تقبل عكس مجموعة block من الأوامر. حيث إن هذا سيكون مُفيد في عكس أجزاء مُعينة فقط من تهجير قُمت به مُسبقًا. على سبيل المثال، إفترض أنك إحتحجت إستخدام تحقيقات السحل النشط على التهجير ExampleMigration في مكان إستخدام CHECK لتأكيد الرقم البريدي zipcode.
class DontUseConstraintForZipcodeValidationMigration < ActiveRecord::Migration[5.0]
def change
revert do
# copy-pasted code from ExampleMigration
reversible do |dir|
dir.up do
# add a CHECK constraint
execute <<-SQL
ALTER TABLE distributors
ADD CONSTRAINT zipchk
CHECK (char_length(zipcode) = 5);
SQL
end
dir.down do
execute <<-SQL
ALTER TABLE distributors
DROP CONSTRAINT zipchk
SQL
end
end
# The rest of the migration was ok
end
end
end
إن نفس التهجير يُمكن كتابته بدون إستخدام revert
و لكن ستقوم بعمل المزيد من الخطوات: عكس ترتيب الأمر create_table
و الأمر reversible
، و إستبدال الأمر create_table
بالأمر drop_table
، و أخيرًا ستقوم بعكس أمرين up
و down
و العكس صحيح. هذا كُله يتم عمله بواسطة دالة revert
.
اقتباس**إذا أردت تُضيف تأكيدات check constraints في المثال أعلاه، و ستقوم بإستعمال ملف
structre.sql
لتخطي هذا.
سنتابع في الدرس التالي ما تبقى من هذا الدليل التعليمي حول تهجير Active Record
المصدر:
توثيقات Ruby on Rails.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.