البرمجة

أنواع الارتباطات في Active Record

Active Record Associations: الارتباطات وأنواعها في إطار العمل روبي أون ريلز

يعتبر إطار العمل روبي أون ريلز (Ruby on Rails) من أشهر أُطر تطوير تطبيقات الويب، ويُعرف بكونه يعتمد على مبدأ البرمجة التي تُركز على التسهيل وتقليل كمية الأكواد، ويُساعد المطورين على بناء تطبيقات سريعة ومرنة. من العناصر الأساسية التي تُسهّل العمل في روبي أون ريلز هي مكتبة Active Record، التي تمثل طبقة نماذج البيانات (Models) وتربط بين البرمجة كائنية التوجه وقاعدة البيانات.

الجزء الأهم في Active Record هو مفهوم الارتباطات (Associations)، حيث تمكّن المطور من ربط الجداول والبيانات بطريقة منظمة وسهلة الاستعلام عنها دون الحاجة لكتابة استعلامات SQL معقدة. هذه الارتباطات تعكس العلاقات بين الكائنات في قاعدة البيانات، وتساهم بشكل كبير في تحسين تصميم قاعدة البيانات وهيكل التطبيق.


مفهوم الارتباطات في Active Record

الارتباطات في Active Record هي علاقات يتم تعريفها بين النماذج (Models) بحيث تعكس العلاقات الحقيقية بين الكيانات في التطبيق. فعلى سبيل المثال، في نظام إدارة مكتبة، قد يكون لدينا نموذج “كتاب” وآخر “مؤلف”، فالعلاقة بينهما يمكن أن تكون “مؤلف لديه العديد من الكتب” و”كل كتاب ينتمي إلى مؤلف واحد”.

تساعد الارتباطات في توضيح هذه الروابط، وتسهيل التعامل مع البيانات، من خلال توفير واجهة برمجية سهلة الاستخدام للتنقل بين الكائنات ذات الصلة، إضافة إلى إنشاء استعلامات محسنة من دون الحاجة إلى التعامل مباشرة مع قواعد البيانات.


أنواع الارتباطات في Active Record

يوجد عدة أنواع من الارتباطات تُستخدم حسب نوع العلاقة بين النماذج، وكل نوع يختلف في طريقة الربط والاستعلام عن البيانات. هذه الأنواع هي:

1. ارتباط “واحد إلى واحد” (has_one / belongs_to)

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

  • has_one: يعرّف علاقة “لديه واحد” بين النموذجين.

  • belongs_to: يعرّف أن هذا النموذج “يتبع” نموذجًا آخر.

مثال عملي:

ruby
class User < ApplicationRecord has_one :profile end class Profile < ApplicationRecord belongs_to :user end

في هذا المثال، كل مستخدم لديه ملف تعريف واحد، وكل ملف تعريف ينتمي إلى مستخدم واحد. هنا، جدول الـ profiles يحتوي على عمود user_id يشير إلى المستخدم المرتبط به.


2. ارتباط “واحد إلى متعدد” (has_many / belongs_to)

هذا النوع من الارتباط يُستخدم عندما يكون لكل سجل في نموذج ما عدة سجلات مرتبطة في نموذج آخر، بينما النموذج الثاني ينتمي إلى سجل واحد فقط من النموذج الأول.

  • has_many: يدل على أن السجل لديه العديد من السجلات المرتبطة في نموذج آخر.

  • belongs_to: يدل على أن السجل ينتمي لسجل واحد فقط من النموذج الأول.

مثال:

ruby
class Author < ApplicationRecord has_many :books end class Book < ApplicationRecord belongs_to :author end

هنا، كل مؤلف يمكن أن يكون لديه العديد من الكتب، لكن كل كتاب مرتبط بمؤلف واحد فقط.


3. ارتباط “عديد إلى العديد” (has_many :through / has_and_belongs_to_many)

هذا النوع من الارتباط يُستخدم عندما يكون هناك علاقة متبادلة حيث يمكن أن يرتبط كل سجل في نموذج ما بالعديد من السجلات في نموذج آخر، والعكس صحيح.

  • has_and_belongs_to_many: علاقة عديد إلى عديد مباشرة بدون نموذج وسيط.

  • has_many :through: علاقة عديد إلى عديد عبر نموذج وسيط يتم التحكم به.

has_and_belongs_to_many (HABTM)

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

مثال:

ruby
class Student < ApplicationRecord has_and_belongs_to_many :courses end class Course < ApplicationRecord has_and_belongs_to_many :students end

يجب وجود جدول وسيط بدون نموذج (عادةً باسم students_courses) يحتوي على مفاتيح أجنبية لكل من الطالب والدورة.

has_many :through

يُستخدم عندما نحتاج إلى معلومات إضافية عن العلاقة نفسها (مثل تاريخ التسجيل، الحالة، إلخ)، حيث نُعرّف نموذج وسيط.

مثال:

ruby
class Physician < ApplicationRecord has_many :appointments has_many :patients, through: :appointments end class Appointment < ApplicationRecord belongs_to :physician belongs_to :patient end class Patient < ApplicationRecord has_many :appointments has_many :physicians, through: :appointments end

هذا يتيح التحكم في تفاصيل العلاقة بين الطبيب والمريض من خلال نموذج “المواعيد”.


4. ارتباط “Polymorphic Associations” – الارتباطات متعددة الأشكال

هي نوع خاص يسمح لنموذج معين بأن يرتبط بعدة نماذج أخرى من أنواع مختلفة باستخدام حقلين معًا: *_id و *_type، بحيث يمكن لنموذج واحد أن يرتبط بأكثر من نوع من النماذج.

مثال:

ruby
class Comment < ApplicationRecord belongs_to :commentable, polymorphic: true end class Post < ApplicationRecord has_many :comments, as: :commentable end class Photo < ApplicationRecord has_many :comments, as: :commentable end

في هذا المثال، يمكن لأي تعليق أن يرتبط إما بمقال (Post) أو بصورة (Photo)، من خلال استخدام الحقلين commentable_id و commentable_type.


كيفية عمل Active Record Associations داخلياً

عند تعريف الارتباطات في نماذج Active Record، يتم توليد عدة وظائف تلقائية تتضمن:

  • دوال الوصول إلى الكائنات المرتبطة مباشرة (مثل user.profile أو author.books).

  • توفير أدوات لتعديل العلاقة (مثل user.create_profile، author.books.build).

  • دعم عمليات الحذف والترابط (مثل dependent: :destroy).

  • إنشاء استعلامات مدمجة (eager loading) لتقليل عدد الاستعلامات على قاعدة البيانات.

عند طلب كائن مرتبط، يقوم Active Record تلقائيًا بإنشاء الاستعلام المناسب باستخدام SQL، ويتم تحميل البيانات المرتبطة، مما يساهم في تحسين الأداء وسهولة البرمجة.


خيارات متقدمة في تعريف الارتباطات

1. dependent

تحدد طريقة التعامل مع السجلات المرتبطة عند حذف السجل الأساسي. من القيم الشائعة:

  • :destroy: حذف السجلات المرتبطة مع تنفيذ callbacks.

  • :delete_all: حذف السجلات المرتبطة مباشرة من قاعدة البيانات بدون تنفيذ callbacks.

  • :nullify: تعيين مفاتيح الارتباط إلى null بدلاً من الحذف.

مثال:

ruby
class Author < ApplicationRecord has_many :books, dependent: :destroy end

2. inverse_of

يساعد على تحسين الأداء في تحميل الكائنات المرتبطة عن طريق تمكين Active Record من معرفة العلاقة العكسية.

3. through

يُستخدم لتعريف علاقات عديد إلى عديد عبر نموذج وسيط كما شرحنا سابقًا.


تحسين الأداء باستخدام الارتباطات

الارتباطات توفر طرقًا للتعامل مع مشاكل الأداء مثل مشكلة N+1 Query، وهي الحالة التي تُنفذ فيها استعلامات متكررة لكل سجل مرتبط.

باستخدام:

  • includes

  • joins

  • eager_load

يمكن تحميل البيانات المرتبطة مسبقًا وتقليل عدد الاستعلامات، مما يجعل التطبيق أسرع وأكثر كفاءة.


تمثيل الارتباطات في قواعد البيانات

غالبًا ما تُترجم الارتباطات في Active Record إلى قواعد بيانات عبر مفاتيح أجنبية (Foreign Keys)، وجداول وسيطة في حالة الارتباطات المعقدة (كعلاقات عديد إلى عديد).

تساعد هذه المفاتيح في الحفاظ على تكامل البيانات ومنع التكرار، كما تسهل عمليات الانضمام بين الجداول في الاستعلامات.


مقارنة بين أنواع الارتباطات

نوع الارتباط الوصف جدول المفتاح الأجنبي وجود جدول وسيط حالات الاستخدام الشائعة
has_one / belongs_to علاقة واحد إلى واحد في النموذج الذي يحتوي على belongs_to لا ملف تعريف المستخدم، عنوان البريد الإلكتروني
has_many / belongs_to علاقة واحد إلى متعدد في النموذج الذي يحتوي على belongs_to لا المؤلف والكتب، المستخدم والمنشورات
has_and_belongs_to_many علاقة متعدد إلى متعدد مباشرة لا، يوجد جدول وسيط فقط نعم الطلاب والدورات التعليمية
has_many :through علاقة متعدد إلى متعدد مع نموذج وسيط نعم، جدول وسيط مع نموذج نعم الأطباء والمرضى مع تفاصيل المواعيد
polymorphic علاقة مرنة مع نماذج متعددة نعم، باستخدام *_id و *_type لا التعليقات على مقالات أو صور

الخلاصة

الارتباطات في Active Record تمثل أحد الركائز الأساسية التي تجعل من روبي أون ريلز إطارًا قويًا ومرنًا لبناء تطبيقات تعتمد على قواعد بيانات معقدة ومتعددة الجداول. من خلال تعريف العلاقات بين النماذج بوضوح، يمكن للمطورين استغلال قدرات Active Record للوصول إلى البيانات بطريقة بسيطة ومنظمة، مع الحفاظ على الأداء العالي وقابلية الصيانة.

إتقان استخدام الارتباطات وأنواعها المتنوعة يتيح بناء تطبيقات قوية تتفاعل بشكل دقيق مع قواعد البيانات، وتقدم تجربة استخدام سلسة وفعالة سواء من ناحية برمجية أو من ناحية الأداء.


المصادر والمراجع

  1. Ruby on Rails Guides – Active Record Associations

    https://guides.rubyonrails.org/association_basics.html

  2. Agile Web Development with Rails – Sam Ruby, Dave Thomas, David Heinemeier Hansson, Pragmatic Bookshelf, 2014.