ruby on rails 105 Active Record Associations: مرجع ارتباط has_one


هشام رزق الله

تابعنا في الدرس السابق من هذه السلسلة مرجع الارتباط المفصّل وسنتابع في هذا الدرس الحديث عن مرجع ارتباط has_one.

4.2 مرجع ارتباط has_one

يُنشئ ارتباط has_one تطابق واحد لواحد (one-to-one) مع كائن آخر، بمصطلحات قاعدة البيانات، هذا الارتباط يعلن أن الصنف الآخر يحتوي على مفتاح خارجي، وإذا كان هذا الصنف يحتوي على مفتاح خارجي، فيجب عليك في هذه الحالة استخدام belongs_to بدلا من ذلك.

4.2.1 الأساليب المضافة بواسطة has_one

عند إعلان ارتباط has_one، فإن الفئة المُعلنة ستحصل على 5 أساليب متعلقة بالارتباط:

  • association
  • (association=(associate
  • ({} = build_association(attributes
  • ({} = create_association(attributes
  • ({} = create_association!(attributes
  • reload_association

في كل هذه الأساليب، يُستبدل الارتباط مع symbol المُمرر كمعامل أول إلى has_one، على سبيل المثال:

class Supplier < ApplicationRecord
  has_one :account
end

فإن كل مثيل من نموذج Supplier سيحصل على هذه الأساليب:

account
account=
build_account
create_account
create_account!
reload_account
Quote

ملاحظة:
يجب عليك عند إنشاء ارتباط has_one أو belongs_to جديد استخدام بادئة _build لبناء الارتباط، بدلا من أسلوب association.build الذي سيستخدم لارتباطات has_many أو has_and_belongs_to_many، ولإنشاء واحد استخدم بادئة _create .

4.2.1.1 association

يُرجع أسلوب association الكائن المرتبط إن وجد، وإلا، فسيرجع nil.

@account = @supplier.account

إذا أُسترد الكائن المرتبط بالفعل من قاعدة البيانات لهذا الكائن، ستٌسترجع النسخة المخبأة، ولتجاوز هذا السلوك(وإجبار قاعدة البيانات على القراءة)، استدعي #reload_association في الكائن الأب.

@account = @supplier.reload_account

4.2.1.2 (association=(associate

يُعيّن أسلوب =association كائن مرتبط إلى هذا الكائن، وفي ما وراء الكواليس، هذا يعني استخراج المفتاح الرئيسي من هذا الكائن وتعيين مفتاح الخارجي للكائن المرتبطة إلى نفس القيمة.

@supplier.account = @account

4.2.1.3 ({} = build_association(attributes

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

@account = @supplier.build_account(terms: "Net 30")

4.2.1.4 ({} = create_association(attributes

يرجع أسلوب create_association كائن جديد من النوع المرتبط، وهذا الكائن سيُنشئ من السمات الممررة، وسيُعين الارتباط بمفتاحه الخارجي، وبمجرد النجاح في جميع التحقيقات (validations) المحددة في النموذج المرتبط، سيُحفظ الكائن المرتبط.

@account = @supplier.create_account(terms: "Net 30")

4.2.1.5 ({} = create_association!(attributes

يعمل كما create_association في الأعلى، لكنه يصدر ActiveRecord::RecordInvalid إذا كان السجل (record) غير صالح.

4-2-2 خيارات has_one

في حين يستخدم Rails الافتراضات الذكية والتي تعمل بشكل جيد في أغلب الأحيان، لكن في بعض الأوقات ستحتاج إلى تخصيص سلوك مرجع ارتباط has_one، ويمكن تحقيق هذه التخصيصات بسهولة عن طريق تمرير الخيارات عند إنشاء الارتباط، فعلى سبيل المثال، يستخدم هذا الارتباط اثنين من هذه الخيارات:

class Supplier < ApplicationRecord
  has_one :account, class_name: "Billing", dependent: :nullify
end

يدعم ارتباط has_one هذه الخيارات:

  • as:
  • autosave:
  • class_name:
  • dependent:
  • foreign_key:
  • inverse_of:
  • primary_key:
  • source:
  • source_type:
  • through:
  • validate:

4.2.2.1 as:

يشير تعيين خيار as: على أن الارتباط متعدد الأشكال، وستجد المزيد من التفاصيل حول الارتباطات متعددة الأشكال بالتفاصيل في الأعلى.

4.2.2.2 autosave:

إذا عيّنت خيار autosave: إلى true، فإن Rails سيحفظ أي أعضاء محملين وسيدمر الأعضاء الذي وُضع عليهما علامة للتدمير كلما حفظت كائن الأب.

4.2.2.3 class_name:

إذا لم يكن بالإمكان اشتقاق اسم النموذج الآخر من اسم الارتباط، يمكنك استخدام خيار class_name: لتوفير اسم النموذج، فعلى سبيل المثال، إذا كان المُورّد يمتلك حساب، لكن اسم النموذج الحالي الذي يحتوي على الحسابات هو Billing، فيمكنك فعل التالي:

class Supplier < ApplicationRecord
  has_one :account, class_name: "Billing"
end

4.2.2.4 dependent:

يتحكم في ما يحدث للكائن المرتبط عند حذف مالكه:

  • destroy: سيدمر كائن المرتبط أيضا.
  • delete: سيحذف الكائن المرتبط مباشرة من قاعدة البيانات (ولن يعمل دوال الاستدعاء).
  • nullify: سيُعين المفتاح الخارجي إلى NULL ولن يعمل دوال الاستدعاء.
  • restrict_with_exception: سيصدر استثناء إذا كان هنالك كائن مرتبط.
  • restrict_with_error: سيضاف خطأ إلى المالك إذا كان هنالك كائن مرتبط.

من الضروري عدم تعيين أو ترك خيار nullify: للارتباطات التي تملك قيود NOT NULL على قاعدة البيانات، إذا لم تعيّن dependent لتدمير هذه الارتباطات فلن تتمكن من تغيير كائن المرتبط لأنه سيُعيّن المفتاح الخارجي للكائن المرتبط الأولي إلى NULL التي هي غير مسموح بها.

4.2.2.5 foreign_key:

بالاتفاق، يفترض Rails أن العمود الذي يحمل المفتاح الخارجي في النموذج الآخر هو اسم النموذج مع إضافة بادئة id_، ويسمح لك خيار :foreign_key بتعيين اسم المفتاح الخارجي مباشرة:

class Supplier < ApplicationRecord
  has_one :account, foreign_key: "supp_id"
end
Quote

تنبيه:
على أي حال، لن ينشئ Rails أعمدة مفتاح خارجي لك، ستحتاج إلى تعريف صريح لهم كجزء من التهجيرات.

4.2.2.6 inverse_of:

يحدد خيار inverse_of: اسم ارتباط belongs_to والذي هو عكس هذا الارتباط، وهذا الخيار لا يعمل في التركيبة مع خيارات through: أو as:.

class Supplier < ApplicationRecord
  has_one :account, inverse_of: :supplier
end
 
class Account < ApplicationRecord
  belongs_to :supplier, inverse_of: :account
end

4.2.2.7 primary_key:

يفترض Rails أن العمود الذي يحمل المفتاح الرئيسي في هذا النموذج هو id، يمكنك تجاوز ذلك وتصريح المفتاح الرئيسي عن طريق خيار primary_key:

4.2.2.8 source:

يحدد خيار source: اسم ارتباط المصدر لارتباط has_one :through.

4.2.2.9 source_type:

يحدد خيار source_type: ارتباط المصدر لارتباط has_one :through الذي يمر عبر ارتباط متعدد الأشكال.

4.2.2.10 through:

يحدد خيار through: نموذج الضم والذي يتم من خلاله تنفيذ الاستعلام، تم الحديث حول has_one :through في وقت سابق من هذا الدليل.

4.2.2.11 validate:

إذا عُيّن خيار validate: إلى true، فسيتحقق من الكائنات المرتبطة كلما حفظت هذا الكائن، افتراضيا، قيمة هذا الخيار هي false، ولن يتحقق مع كائنات المرتبطة عند حفظ هذا الكائن.

4.2.3 نطاقات Scopes لـ belongs_to

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

class Supplier < ApplicationRecord
  has_one :account, -> { where active: true }
end

يمكنك استخدام أي من أساليب الاستعلامات القياسية داخل كتلة scope، وستجد تفاصيلها في الأسفل:

  • where
  • includes
  • readonly
  • select

4.2.3.1 where

يسمح لك أسلوب where بتحديد شروط الكائن المرتبط.

class Supplier < ApplicationRecord
  has_one :account, -> { where "confirmed = 1" }
end

4.2.3.2 includes

يمكنك استخدام أسلوب includes لتحديد الارتباطات من الدرجة الثانية التي تريد تحميلها (eager-loaded) عند استخدام هذا الارتباط، فعلى سبيل المثال، فكر في هذه النماذج:

class Supplier < ApplicationRecord
  has_one :account
end
 
class Account < ApplicationRecord
  belongs_to :supplier
  belongs_to :representative
end
 
class Representative < ApplicationRecord
  has_many :accounts
end

إذا كنت تسترد الممثلين مباشرة من المُوردين بشكل كثير (supplier.account.representative@)، فيمكنك جعل شيفرتك البرمجية أكثر كفاءة من خلال تضمين الممثلين إلى الارتباط من المُوردين إلى الحسابات:

class Supplier < ApplicationRecord
  has_one :account, -> { includes :representative }
end
 
class Account < ApplicationRecord
  belongs_to :supplier
  belongs_to :representative
end
 
class Representative < ApplicationRecord
  has_many :accounts
end

4.2.3.3 readonly

سيكون الكائن المرتبط للقراءة فقط عند استرداده عن طريق الارتباط إذا استخدمت readonly.

4.2.3.4 select

يسمح لك أسلوب select بتجاوز جملة SELECT (في SQL) والتي تُستخدم لاسترداد البيانات حول الكائن المرتبط، وبشكل افتراضي، سيسترد Rails جميع الأعمدة.

4.2.4 هل توجد أية كائنات مرتبطة؟

يمكنك معرفة هل توجد أية كائنات مرتبطة عن طريقة استخدام أسلوب ?association.nil

if @supplier.account.nil?
  @msg = "No account found for this supplier"
end

4.2.5 متى تحفظ الكائنات؟

عند تعيين كائن إلى ارتباط has_one، سيُحفظ ذلك الكائن بشكل تلقائي (من أجل تحديث مفتاحه الخارجي)، بالإضافة إلى ذلك، يُحفظ أي كائن أُستبدل بشكل تلقائي لأن المفتاح الخارجي سيتغير أيضا.
إذا فشلت عملية الحفظ بسبب أخطاء تحقق (validation)، فإن إعلان التعيين سيرجع false ويُلغى التعيين نفسه.
إذا لم يُحفظ (سترجع ?new_record قيمة false) الكائن الأب (الذي يعلن ارتباطhas_one )، فإن الكائنات الأبناء لن يُحفظوا أيضا، وسيُحفظون تلقائيا عند حفظ الكائن الأب.
إذا أردت تعيين كائن إلى ارتباط has_one بدون حفظ الكائن، استخدم أسلوب association.build.

وسنتابع في الدرس القادم شرح مرجع ارتباط has_many (الأساليب المضافة والخيارات).

 

المصدر:
توثيقات Ruby on Rails





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


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



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

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

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


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

تسجيل الدخول

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


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