أساسيات السجل الفعال في ريلز
هذا الدليل هو مدخل إلى السجل الفعَّال (Active Record). بعد قراءة هذا الدليل، ستتعرف على:
- ما هي تقنية ORM (اختصار للعبارة Object Relational Mapping أي "ربط الكائنات العِلاقيَّة") والسجل الفعَّال وكيفية استعمالهما في ريلز.
- كيف ينسجم السجل الفعَّال مع النموذج MVC (اختصار للعبارة Model-View-Controller).
- كيفية استعمال نماذج السجل الفعَّال (Active Record models) لمعالجة وتعديل البيانات المخزَّنة في قاعدة بيانات عِلاقيِّة (relational database).
- اصطلاحات تسمية مخطَّط السجل الفعَّال.
- مفهوم تهجيرات، وتحققات، وردود نداء قاعدة البيانات.
ما هو السجل الفعال؟
إن السجل الفعال هو الحرف M في MVC - أي "النموذج" (Model)، الذي يعبر عن الطبقة المسؤولة عن تمثيل منطق العمل وبياناته في النظام. يسهّل السجل الفعال عمليّة إنشاء واستخدام الكائنات التي يجب المحافظة على بياناتها في قاعدة بيانات. السجل الفعال هو تنفيذ "لنمط السجل الفعال" (Active Record Pattern)، والذي يعبر بذاته عن نظام ربط الكائنات بالعلاقات (Object Relational Mapping).
نمط السجل الفعال
شُرح نمط عمل السجل الفعال من قبل مارتن فولر (Martin Fowler) في كتابه "أنماط معمارية التطبيقات المؤسساتية" (Patterns of Enterprise Application Architecture). في السجل الفعال، تحمل الكائنات البيانات المحفوظة والسلوك المنفذ على هذه البيانات. يأخذ السجل الفعال بالحسبان الرأي الذي ينص على أن ضمان الوصول للبيانات عبر جزء من الكائن سيجعل المستخدمين على دراية بهذا الكائن وكيفية قراءة وكتابة البيانات من وعلى قاعدة البيانات.
ربط الكائنات بالعلاقات
إن ربط الكائنات بالعلاقات، وكما يُرمز له اختصارًا ORM، هو عبارة عن طريقة لربط الكائنات الخاصة بتطبيقٍ ما بجداول في نظام إدارة قواعد بيانات علائقية. باستخدام هذا النظام، يمكن تخزين وقراءة الخاصيات والعلاقات من قاعدة البيانات بسهولة دون الحاجة لكتابة تعليمات SQL مباشرةً.
ملاحظة: إذا لم تكن ملمًا بأنظمة إدارة قواعد البيانات العلائقية، أو بلغة الاستعلام البنيوية SQL، يرجى الاطلاع على توثيق لغة SQL أو الاطلاع هذا المقال (والمقالات الأخرى حول SQL في أكاديمية حسوب). إن فهم طريقة عمل قواعد البيانات العلائقية مهم جدًا لفهم السجلات الفعالة في ريلز بشكل عام.
السجل الفعال كإطار عمل ORM
يزوّد السجل الفعال بمجموعة من المهام، أهمها القابلية على:
- تمثيل النماذج (models) وبياناتها.
- تمثيل العلاقات بين هذه النماذج.
- تمثيل هيكلية الوراثة الهرمية (inheritance hierarchies) بين النماذج المتعددة.
- التحقق من النماذج قبل حفظها في قاعدة البيانات.
- تنفيذ عمليات قواعد البيانات بشكل غرضي التوجه.
العرف مقابل الضبط في السجل الفعال
عند كتابة التطبيقات باستخدام لغات برمجة أو واجهات عمل أخرى، قد يكون من الضروري كتابة الكثير من تعليمات التهيئة والضبط الضرورية لعمل التطبيق. يعد ذلك صحيحًا من أجل واجهات عمل ORM بشكل عام. لكن إذا اتبعت العرف المتبنى من قبل ريلز، فستحتاج إلى كتابة القليل من تعليمات التهيئة (وبعض الأوقات قد لا تحتاج إلى كتابة تهيئة مطلقًا) عند إنشاء نماذج السجل الفعال. تصب الفكرة في حال هيأت تطبيقك بالطريقة ذاتها معظم الوقت، فتلك الطريقة يجب أن تكون الطريقة الافتراضية. لذلك، ستحتاج إلى التهيئات الصريحة فقط في تلك الحالات التي لا تستطيع فيها التقيّد بالأعراف المعيارية (standard convention).
أعراف التسمية
بشكل افتراضي، يستخدم السجل الفعال بعض أعراف (اصطلاحات) التسمية للحاجة إلى الربط بين النماذج وجداول قاعدة البيانات. يجمع ريلز أسماء الأصناف لمعرفة أسماء الجداول. لذا، من أجل الصنف Book
، يجب أن تنشئ جدولًا في قاعدة البيانات يسمّى books
. تعد طريقة الجمع الخاصة بريلز طريقةً قويةً جدًا، والتي تمكّنك من جمع الكلمات النظامية والشاذة. عند استخدام أسماء الأصناف المكوّنة من كلمتين أو أكثر، يجب أن يراعي اسم النموذج أعراف لغة روبي، وذلك باستخدام نمط سنام الجمل (CamelCase)، بينما يجب على أسماء الجداول أن تحوي الكلمات مفصولة بواسطة علامة الترقيم "_". أمثلة:
- جدول قاعدة بيانات: جمع مع علامة ترقيم "_" تفصل الكلمات (مثال: book_clubs).
- صنف النموذج
Model
: مفرد مع أول حرف كبير من كل كلمة (مثال: BookClub).
النموذج/الصنف | الجدول/المخطط |
---|---|
Article | articles |
LineItem | line_items |
Deer | deers |
Mouse | mice |
Person | people |
أعراف المخطط
يستخدم السجل الفعال بعض أعراف التسمية من أجل الحقول في قواعد البيانات، وذلك بناءً على الهدف من هذه الحقول.
- المفاتيح الأجنبية (Foreign keys): يجب على هذه الحقول أن تراعي النمط التالي "مُعرِّف_اسم_الجدول_المفرد_id" (مثال: item_id، order_id). هذه هي الحقول التي يجب على السجل الفعال النظر إليها عند إنشاء العلاقات بين النماذج.
- المفاتيح الرئيسية (Primary keys): بشكل افتراضي، يستخدم السجل الفعال حقل العدد الصحيح المسمى id كالمفتاح الرئيسي للجدول. عند استخدام ترحيلات السجل الفعال لإنشاء جداولك، سيتم إنشاء هذا الحقل تلقائيًا.
هناك مجموعة من الحقول الاختيارية التي تضيف ميزات إضافية إلى كائنات السجل الفعال:
- الحقل
created_at
: يعيّن تلقائيًا تاريخ إنشاء السجل. - الحقل
updated_at
: يعيّن تلقائيًا تاريخ تعديل السجل. - الحقل
lock_version
: يضيف القفل الذكي إلى نموذج. - الحقل
type
: يحدّد أن النموذج يستخدم وراثة الجدول الوحيد. - الحقل
(association_name)_type
: يخزن النوع من أجل العلاقات متعددة الأشكال. - الحقل
(table_name)_count
: يستخدم للتخزين المؤقت لعدد الكائنات المرتبطة في العلاقات. مثلًا، إن الحقلcomments_count
في الصنفArticle
الذي يملك عدة نُسخ منComment
سيخزّن عدد التعليقات المرتبطة بكل مقالة.
ملاحظة: في حين أن هذه الحقول اختيارية، فهي حقيقةً محجوزةً من قبل السجل الفعال. تجنب تسمية الحقول بأسماء محجوزة إلى في حال أردت المزيد من الفعالية. مثلًا، الكلمة type
هي كلمة محجوزة تستخدم لوراثة الجدول الوحيد. في حال لم تكن مستخدمًا لهذه الوراثة، حاول المجيء بأسماء مختلفة مثل "context"، والتي تعبر بشكل دقيق عن البيانات التي تُنمذَج (modeling).
إنشاء نماذج السجل الفعال
من السهل جدًا إنشاء نماذج السجل الفعال. كل ما يتوجب عليك فعله هو إنشاء صنف فرعي يرث من الصنف ApplicationRecord
:
class Product < ApplicationRecord
end
سينشئ هذا النموذج Product
، الذي يربط بالجدول products
في قاعدة البيانات. عن طريق هذا الصنف، يمكنك أيضًا ربط الحقول في كل سطر من أسطر الجدول بخاصّيات ضمن النموذج. بفرض أن الجدول products
تم إنشاؤه عن طريق تنفيذ تعليمة SQL التالية:
CREATE TABLE products (
id int(11) NOT NULL auto_increment,
name varchar(255),
PRIMARY KEY (id)
);
تنشئ هذه التعليمة جدولًا بعمودين، id
و name
. كل سطر من هذا العامود يمثل منتجًا بهذين الوسيطين. وبالتالي، عليك أن تكتب التعليمات التالية لإنشاء سطر جديد:
p = Product.new
p.name = "Some Book"
puts p.name # "Some Book"
تجاوز أعراف التسمية
ماذا لو أردت اتباع أعراف تسمية مختلفة أو أردت استخدام تطبيقك المكتوب بريلز مع قاعدة بيانات قديمة؟ ليست مشكلة، يمكنك بسهولة تجاوز أعراف التسمية.
يرث الصنف ApplicationRecord
من الصنف ActiveRecord::Base
، الذي يعرّف مجموعة من الطرق المساعدة. يمكنك استخدام التابع ActiveRecord::Base.table_name=
لتحديد اسم الجدول الذي يجب استخدامه.
class Product < ApplicationRecord
self.table_name = "my_products"
end
إذا فعلت ذلك، عليك أن تحدد بشكل يدوي اسم الصنف الذي يحوي التجهيزات (my_products.yml)، باستخدام التابع set_fixture_class
في تعريف الاختبار:
class ProductTest < ActiveSupport::TestCase
set_fixture_class my_products: Product
fixtures :my_products
...
end
من الممكن تجاوز العمود الذي يستخدم مفتاحًا رئيسيًا للجدول باستخدام التابع ActiveRecord::Base.primary_key
:
class Product < ApplicationRecord
self.primary_key = "product_id"
end
العمليات CRUD: قراءة وكتابة البيانات
المصطلح CRUD هو اختصار لأربع عمليات مستخدمة على البيانات: إنشاء (Create)، قراءة (Read)، تحديث (Update)، وحذف (Delete). تلقائيًا، ينشئ السجل الفعال توابعًا لإتاحة قراء وكتابة البيانات المخزنة في قواعد البيانات.
الإنشاء
يمكن إنشاء كائنات السجل الفعال من جدول Hash أو كتلة أو من خلال تعيين الخاصيات بشكل يدوي بعد الإنشاء. يعيد التابع new
كائنًا جديدًا، بينما يعيد التابع create
الكائن ويحفظه مباشرةً في قاعدة البيانات.
على سبيل المثال، بفرض النموذج User
الذي يحوي على الخاصيات name
و occupation
، يمكن استخدام التابع create
لإنشاء وحفظ سجل جديد في قاعدة البيانات.
user = User.create(name: "David", occupation: "Code Artist")
أما باستخدام التابع new
، يمكن إنشاء الكائن دون حفظه في قاعدة البيانات.
user = User.new
user.name = "David"
user.occupation = "Code Artist"
بعد ذلك، يمكن حفظ السجل في قاعدة البيانات باستخدام التابع user.save
.
أخيرًا وليس آخرًا، إذا تم إعطاء كتلةٍ، فالكائن الجديد الناتج عن التابعين create
و new
يمرَّر إلى تلك كتلة من أجل عملية التهيئة:
user = User.new do |u|
u.name = "David"
u.occupation = "Code Artist"
end
القراءة
يزوّد السجل الفعال بواجهة برمجية غنية من أجل قراءة البيانات من قواعد البيانات. فيما يلي مجموعة من الأمثلة المختلفة حول وصول البيانات المزودة من قبل السجل الفعال:
# تعيد مجموعة تحوي كل المستخدمين
users = User.all
# تعيد أول مستخدم
user = User.first
# David تعيد أول مستخدم اسمه
david = User.find_by(name: 'David')
# Code Artists والأعمال David البحث عن جميع المستخدمين ذوي الأسماء
# تنازليًا created_at والترتيب بواسطة الحقل
users = User.where(name: 'David', occupation: 'Code Artist').order(created_at: :desc)
يمكنك قراءة المزيد حول الاستعلامات باستخدام السجل الفعال في توثيق واجهة استعلامات السجل الفعال.
التحديث
بعد إعادة كائن السجل الفعال، يمكن تعديل خاصياته ومن ثم حفظه في قاعدة البيانات:
user = User.find_by(name: 'David')
user.name = 'Dave'
user.save
اختصارًا لهذه التعليمات، يمكن استخدام الطريقة التالية:
user = User.find_by(name: 'David')
user.update(name: 'Dave')
يكون هذا مفيدًا عند تحديث مجموعة من الخاصيات بآن واحد. في حال أردت تحديث مجموعة من السجلات بدفعة واحدة، يمكنك استخدام التابع update_all
.
User.update_all "max_login_attempts = 3, must_change_password = 'true'"
الحذف
بالمثل، عند استرجاع كائن السجل الفعال، يمكن حذفه من قاعدة البيانات كالتالي:
user = User.find_by(name: 'David')
user.destroy
في حال أردت حذف مجموعة من السجلات دفعة واحدة، يمكنك استخدام التابع destroy_all
.
# وحذفه David البحث عن المستخدم ذي الاسم
User.where(name: 'David').destroy_all
# حذف جميع المستخدمين
User.destroy_all
التحقق
يمكنك السجل الفعال من التحقق من حالة السجل قبل حفظه في قاعدة البيانات. هناك مجموعة من الطرق التي يمكنك استخدامها للتحقق من سجلك والتأكد من أن الخاصيات ليست فارغة، أو ليست مكررة، أو تتبع نسق معين، والمزيد من عمليات التحقق.
إن عملية التحقق من صحة السجلات هي عملية مهمة جدًا عند الحفظ في قاعدة البيانات، وبالتالي يأخذ التابع save
و update
هذه العمليات بالحسبان عند العمل: إذ يعيد هذين التابعين القيمة false
عند فشل التحقق، ولا تنفذ أية عمليات على قاعدة البيانات. يمكن تجاوز هذا التصرف عن طريق التابعين save!
و update!
، التي تعتبر أشد وأكثر صرامة، إذ ترمي استثناءً من النوع ActiveRecord::RecordInvalid
في حال فشل عملية التحقق. على سبيل المثال:
class User < ApplicationRecord
validates :name, presence: true
end
user = User.new
user.save # => false
user.save! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank
يمكنك قراءة المزيد حول هذا الموضوع في دليل التحقق من صحة السجل الفعَّال.
توابع رد النداء (Callbacks)
تتيح توابع رد النداء الخاصة بالسجل الفعال إمكانية ربط تعليمات معينة بأحداث مخصصة في دورة حياة النموذج. يمكّنك ذلك من إضافة السلوك لنماذجك عن طريق تنفيذ التعليمات بشكل خفي عند إطلاق هذه الأحداث، مثلًا عند إنشاء سجل جديد، أو تحديثه أو حذفه. يمكنك تعلم المزيد عن توابع رد النداء في دليل ردود نداء السجل الفعال.
التهجيرات
يزوّد ريلز بلغة ذات نطاق لإدارة مخططات قواعد البيانات التي تدعى "بالتهجيرات" (migrations). تُخزّن التهجيرات في ملفات، وتنفّذ على قواعد البيانات التي يدعمها السجل الفعال بواسطة rake
. في الملف التالي تهجير ينشئ جدولًا:
class CreatePublications < ActiveRecord::Migration[5.0]
def change
create_table :publications do |t|
t.string :title
t.text :description
t.references :publication_type
t.integer :publisher_id
t.string :publisher_type
t.boolean :single_issue
t.timestamps
end
add_index :publications, :publication_type_id
end
end
يستمر ريلز في تعقُّب حالة الملفات المحفوظة في قاعدة البيانات، ويزوّد بطريقة لإعادة حالة التهجير. لتنفيذ التهجير، يمكنك استخدام الأمر rails db:migrate
، ولإعادته، يمكنك استخدام الأمر rails db:rollback
.
الجدير بالملاحظة أنَّ التعليمات السابقة هي حيادية لقواعد البيانات، إذ يمكن تنفيذها على قواعد البيانات من نوع MySQL أو PostgreSQL أو Oracle أو العديد من قواعد البيانات الأخرى. يمكنك تعلّم المزيد عن التهجيرات في دليل التهجيرات الخاصة بالسجل الفعال.