ruby on rails 102 Active Record Migrations: نظرة عامة وطريقة إنشائه


Mahmoud Gamea

إن التهجير من أهم مزايا Active Record، حيث يسمح لك بتطوير قاعدة البيانات بسهولة مع مرور الزمن. فبدلًا من إعادة كتابة مُخططات قاعدة البيانات بسطور SQL من جديد، سيسمح لك التهجير باستعمال كود Ruby موحد المجال Domain – specific language لوصف التعديلات اللازمة التي ستقوم بها على جداولك.

1 نظرة عامة على التهجير

التهجير هو الطريقة الملائمة لتبديل أجزاء و مُخططات قاعدة البيانات بمرور الزمن بطريقة سهلة و متناسقة. ونقوم بإستعمال لُغة Ruby موحدة المجال DSL بدلًا من كتابة العديد من سطور SQL مما يسمح للتغيرات بأن تكون مُستقلة تمامًا عن قاعدة البيانات و لا تؤثر عليها سلبًا.
يُمكنك التفكير في التهجير على أنه عمل تحديث جديد لقاعدة البيانات. ففي بداية الإسكيما تكون فارغة، ثُم بعد ذلك تقوم عمليات التهجير بإضافة الجداول، العواميد، أو المدخلات. و Active Record يقوم بعمل هذه التحديثات على الإسكيما من الحالة التي كانت عليها قبل التحديث (أو في النُسخة السابقة). كما سيقوم Active Record بتحديث ملف db/schema.rb ليُناسب بناء قاعدة البيانات بعد التحديث.
مثال على التهجير

class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end

في المثال السابق، قُمنا بعملية تهجير حيث أضفنا جدول جديد يُسمى products يحتوي على عامود نصي يُسمى name و عامود آخر يُسمى description. وسيتم إضافة عامود مفتاح أساسي يُسمى id ضمنيًا، لأنه –كما علمنا من قبل- المفتاح الرئيسي الإفتراضي لجميع نماذج Active Record. آما أمر timestamps يُضيف عامودين، صُنع في created_at وتم تحديثه في updated_at. و تلك العواميد الخاصة يتم إدارتها و تحديثها تلقائيًا بواسطة Active Record.
لاحظ أن عملية التغير التي نقوم بها تتحرك أمامًا مع مرور الوقت، فقبل تشغيل التهجير run migration لن يوجد لدينا ذلك الجدول، و بمجرد تشغيل كود التهجير سنحصل على الجدول، و العكس صحيح! فإن Active Record يُمكنه عكس عملية التهجير بإستخدام أمر العودة Roll back و سيُحذف الجدول الجديد.
بعض قواعد البيانات تدعم الصفقات Transactions* مع التغيرات التي تحدث للإسكيما. خاصية التهجير مُحاطة بتلك الصفقات Transactions. و لكن إذا كانت قاعدة البيانات لا تسمح بالصفقات، فإن التهجير سيقوم بإلغاء الأجزاء التي لم تطرأ عليها تلك التغيرات.
*الصفقات Transaction هي سلسلة من العمليات تتم على وحدة مُفردة من قاعدة البيانات. و تكون مُستقلة تمامًا عن باقي العمليات.

Quote

مثال: بعض السجلات Queries لا تعمل داخل تلك الصفقات، فيمكنك تعطيل خاصية تلك الصفقات Transactions بإستخدام الأمر disable_ddl_transaction! ثُم يُمكنك إستخدام التهجير بعد ذلك.
أما إذا رغبت بعمل التهجير على شيئًا ما، لا يدعم Active Record العمليات العكسية بهذا الشيئ، فُيمكنك إستخدام أمر reversible.

class ChangeProductsPrice < ActiveRecord::Migration[5.0]
  def change
    reversible do |dir|
      change_table :products do |t|
        dir.up   { t.change :price, :string }
        dir.down { t.change :price, :integer }
      end
    end
  end
end

و بدلًا من إستخدام أمر change ستستخدم أوامر up و down.

class ChangeProductsPrice < ActiveRecord::Migration[5.0]
  def up
    change_table :products do |t|
      t.change :price, :string
    end
  end

  def down
    change_table :products do |t|
      t.change :price, :integer
    end
  end
end

2 إنشاء التهجير

2.1 إنشاء تهجير مُستقل و مُنفرد بنفسه

إن عمليات التهجير تكون مُخزنة داخل ملف يوجد في db/migrate، و يوجد ملف لكل عملية تهجير حدثت على فئة مُعينة class. إسم الملف يتخذ الصيغة الآتية YYYYMMDDHHMMSS_creat_products.rb و هي تحتوي على صيغة الوقت التي حدث فيه التهجير، ثم علامة “_” ثم إسم عملية التهجير. إن هذا الإسم يجب أن يُطابق إسم الفئة class التي لحق بها, فعلى سبيل المثال، إن كان إسم التهجير 20080906120000_creat_products.rb فيجب أن يُعرف فئة class إسمها CreatProducts. آما بالنسبة للوقت المُلحق بالإسم، فإن Rails تستعمله لترتيب التهجيرات و ترتيب كيفية عملها. لذلك إذا قُمت بنسخ تهجير ما من تطبيق آخر. فيجب أن تلتفت لهذا الآمر.
و حساب الوقت بالضبط أي الدقيقة و الثانية لأمرٌ صعب. لذلك يوفر Active Record مولد لصُنع هذا الأمر.

$ bin/rails generate migration AddPartNumberToProducts

سيصنع الكود أعلاه تهجير فارغ، لكنه مُسمى بتسمية صحيحة.

class AddPartNumberToProducts < ActiveRecord::Migration[5.0]
  def change
  end
end

إذا كان التهجير على هيئة AddXXXToYYY أو RemoveXXXfromYYY أي يحتوي على أوامر إضافة أو حذف و يحتوي أيضًا على عواميد تحتوي على الأسماء names و الأنواع types، فسيتم صُنع عواميد مُناسبة مثل add_column و remove_column. و الكود أدناه مثال على ذلك.

$ bin/rails generate migration AddPartNumberToProducts part_number:string

سينتج عنه:

class AddPartNumberToProducts < ActiveRecord::Migration[5.0]
  def change
    add_column :products, :part_number, :string
  end
end

و يُمكنك أيضًا عمل فهرسة للعواميد الجديدة.

$ bin/rails generate migration AddPartNumberToProducts part_number:string:index

سينتج عنه:

class AddPartNumberToProducts < ActiveRecord::Migration[5.0]
  def change
    add_column :products, :part_number, :string
    add_index :products, :part_number
  end
end

و بنفس الطريقة يُمكنك عمل تهجير ليزيل عامود بإستخدام هذا الكود.

$ bin/rails generate migration RemovePartNumberFromProducts part_number:string

سينتج عنه:

class RemovePartNumberFromProducts < ActiveRecord::Migration[5.0]
  def change
    remove_column :products, :part_number, :string
  end
end

كما أنك لست مُقيد بنوع واحد من العواميد لإنتاجه، مثال على ذلك

$ bin/rails generate migration AddDetailsToProducts part_number:string price:decimal

سينتج عنه

class AddDetailsToProducts < ActiveRecord::Migration[5.0]
  def change
    add_column :products, :part_number, :string
    add_column :products, :price, :decimal
  end
end

لاحظ هُنا تحديد نوع البيانات الذي قُمنا به
أما إذا كان التهجير يتخذ صيغة CreateXXX و مُتبع بقائمة بأسماء و أنواع العواميد، فإن التهجير سيقوم بعمل جدول XXX يحتوي على تلك العواميد، مثال:

$ bin/rails generate migration CreateProducts name:string part_number:string

و هذا سينتج عنه:

class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.string :part_number
    end
  end
end

وكالعادة، فإنه يُمكنك تعديل ما يتم توليده من قبل التهجير عن طريق الإضافة و الحذف. عند طريق التعديل على هذا الملف db/migrate/YYYMMDDHHMMSS_add_details_to_products.rb، على سبيل المثال:

$ bin/rails generate migration AddUserRefToProducts user:references

و هذا سينتج عنه:

class AddUserRefToProducts < ActiveRecord::Migration[5.0]
  def change
    add_reference :products, :user, foreign_key: true
  end
end

هذا التهجير سوف يصنع عامود user_id مع فهرس مُناسب. و هُناك أيضًا العديد من الخيارات الأخرى لدالة add_reference سنتطرق إليها فيما بعد.
هذا الكود سيولد جداول مُدمجة Join tables إذا إستعملت JoinTable كجزء من إسم التهجير، مثال:
الجداول المُدمجة Join Tables هي تجميع لعدد معين من العواميد من جدول واحد أو أكثر من جدول.

$ bin/rails g migration CreateJoinTableCustomerProduct customer product

و هذا سوف ينتج التهجير الآتي:

class CreateJoinTableCustomerProduct < ActiveRecord::Migration[5.0]
  def change
    create_join_table :customers, :products do |t|
      # t.index [:customer_id, :product_id]
      # t.index [:product_id, :customer_id]
    end
  end
end

2.2 موالدات النماذج

إن مولدات النماذج و الإسكافولد Model and Scaffold Generators يُمكنها صُنع التهجير المُناسب لإضافة نموذج جديد. حيث سيحتوي التهجير على التعليمات اللازمة لصناعة الجداول المُناسبة. فإذا حددت العواميد التي تريدها، سيتم إضافة سطور الكود اللازمة لإضافة تلك العواميد، مثال:
** الإسكافولد Scaffold هو جزء من النمط البرمجي MVC حيثُ يُمكنك إختيار جزء مُعين من قاعدة البيانات للعمل عليه.
** النموذج Model : -حتى لا ننسى- فإنه الجزء الرئيسي من النمط البرمجي MVC و هو الجزء المسئول عن البيانات، المنطق في التعامل و أوامر التطبيقات، و هو مُنفصل تمامًا عن قاعدة البيانات.

$ bin/rails generate model Product name:string description:text

و ذلك سوف يصنع هذا التهجير:

class CreateProducts < ActiveRecord::Migration[5.0]
  def change
    create_table :products do |t|
      t.string :name
      t.text :description

      t.timestamps
    end
  end
end

و بالطبع يُمكنك إضافة أي عدد تشاءه

2.3 تعدية المُعدلات

يُمكنك كتابة كود لتعدي المُعدلات Modifiers لأنهم قد تُقيدك.
فإذا قُمت بتشغيل هذا الكود:

$ bin/rails generate migration AddDetailsToProducts 'price:decimal{5,2}' supplier:references{polymorphic}

سوف يُنتج هذا التهجير:

class AddDetailsToProducts < ActiveRecord::Migration[5.0]
  def change
    add_column :products, :price, :decimal, precision: 5, scale: 2
    add_reference :products, :supplier, polymorphic: true
  end
end

سنتابع في الدروس القادمة بقية أجزاء دليل تعليم Active Record Migrations..
المصدر:
توثيقات Ruby on Rails.





تفاعل الأعضاء


لا توجد أيّة تعليقات بعد



يجب أن تكون عضوًا لدينا لتتمكّن من التعليق

انشاء حساب جديد

يستغرق التسجيل بضع ثوان فقط


سجّل حسابًا جديدًا

تسجيل الدخول

تملك حسابا مسجّلا بالفعل؟


سجّل دخولك الآن