Muhammad Ashraf

الأعضاء
  • المساهمات

    11
  • تاريخ الانضمام

  • تاريخ آخر زيارة

السُّمعة بالموقع

0 Neutral
  1. في الدرسين السابقين ألقينا نظرة عامة حول التحقيقات في Active Record وتعرّفنا على مساعدات التحقيقات وتعرّفنا أيضًا على الخيارات الشائعة وأنواع التحقيقات وسنتابع في هذا الدرس ما تبقى من هذا الدليل التعليمي . 6 أداء/تنفيذ تحقيقات مخصّصة Performing Custom Validations عندما لا تكون التحقيقات المدمجة كافية لاحتياجاتك يمكنك كتابة محققاتك الخاصّة أو وسائل تحقيق كما تفضّل. 6.1 المحققات المخصّصة Custom Validators المحققات المخصصة عبارة عن فئات تقتبس من ActiveModel : :Validator. تلك الفئات يجب أن تنفّذ وسيلة validate التي تأخذ سجل كـتعبير و تُؤدّي التحقيق عليه. يُستدعى المحقق الخاص باستخدام وسيلة validates_with. class MyValidator < ActiveModel::Validator def validate(record) unless record.name.starts_with? 'X' record.errors[:name] << 'Need a name starting with X please!' end end end class Person include ActiveModel::Validations validates_with MyValidator end أسهل طريقة لإضافة محققات مخصّصة للتحقق من خصائص شخصيّة تكون ب ActiveModel: :EachValidator مناسب. في هذه الحالة يجب أن ينفّذ المتحقق الخاص وسيلة validate_each ، التي تأخذ ثلاثة تعبيرات: سجل و خاصّية و قيمة. يتم إدارتهم مع ما يناسبهم: الخاصّية يتم التحقق منها ، و قيمة الخاصّية يتم تجاوزها. class EmailValidator < ActiveModel::EachValidator def validate_each(record, attribute, value) unless value =~ /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\z/i record.errors[attribute] << (options[:message] || "is not an email") end end end class Person < ApplicationRecord validates :email, presence: true, email: true end كما هو موضّح بالمثال يمكن دمج/ربط محقّقات أساسيّة بمحقّقاتك الخاصّة. 6.2 الوسائل المخصّصة يمكنك أيضًا إنشاء وسائل تؤكّد على حالة النموذج و تضيف رسائل إلى الـ errorscollection عندما يكونوا غير صالحين. يجب أن تسجّل بعد ذلك تلك الوسائل باستخدام فئة validate (API) ، مرورًا بالرموز الخاصة بأسماء وسائل التحقيق. يمكنك تمرير/إرسال أكثر من رمز واحد لكل وسيلة لفئة و سيجري التحقيقات المخصصة في نفس الترتيب الذي سُجّلوا به. وسيلة valid? سوف تؤكّد أن مجموعة الأخطاء فارغة ؛ لذلك يجب أن تضيف تحقيقاتك المخصّصة أخطاء إليها عندما ترغب أن يفشل التحقيق. class Invoice < ApplicationRecord validate :expiration_date_cannot_be_in_the_past, :discount_cannot_be_greater_than_total_value def expiration_date_cannot_be_in_the_past if expiration_date.present? && expiration_date < Date.today errors.add(:expiration_date, "can't be in the past") end end def discount_cannot_be_greater_than_total_value if discount > total_value errors.add(:discount, "can't be greater than total value") end end end كما هي مضبُوطة افتراضيّا ، سوف تعمل هذه التحقيقات كل مرّة تستدعي valid? أو تحفظ الكائن. لكن من الممكن أيضًا التحكم في وقت عمل هذه التحقيقات بإعطاء خيار an : on إلى وسيلة validate اما بـ :create أو :update class Invoice < ApplicationRecord validate :active_customer, on: :create def active_customer errors.add(:customer_id, "is not active") unless customer.active? end end 7 التعامل مع أخطاء التحقيق Working with Validation Errors بالإضافة إلى وسائل valid? و invalid? التي تم شرحها مُسبقا ، يدعم Rails عددًا من الوسائل للتعامل مع مجموعة الأخطاء و يحقق في صحّة الكائن. 7.1 الأخطاء Errors ترجع فئة ActiveModel : : Errors يحتوي على كل الأخطاء. كل مفتاح هو اسم الخاصّية و القيمة في مجموعة مصفوفة من المتسلسلات النصّية بالأخطاء. class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end person = Person.new person.valid? # => false person.errors.messages # => {:name=>["can't be blank", "is too short (minimum is 3 characters)"]} person = Person.new(name: "John Doe") person.valid? # => true person.errors.messages # => {} 7.2 الأخطاء [] Errors تستخدم errors عندما تريد أن تفحص رسالة الخطأ لخاصّية معيّنة. تقوم بالرد بمجموعة مصفوفة من المتسلسلات النصّية بكل رسائل الأخطاء لخاصّية مُعيّنة ، كل متسلسلة برسالة خطأ واحدة. لو لم يكن هناك أخطاء مرتبطة بالخاصّية ، تقوم بالرد بمصفوفة فارغة. class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end person = Person.new(name: "John Doe") person.valid? # => true person.errors[:name] # => [] person = Person.new(name: "JD") person.valid? # => false person.errors[:name] # => ["is too short (minimum is 3 characters)"] person = Person.new person.valid? # => false person.errors[:name] # => ["can't be blank", "is too short (minimum is 3 characters)"] 7.3 إضافة الأخطاء errors.add تجعلك وسيلة add أن تضيف رسالة خطأ مرتبطة بخاصّية مُعيّنة. تقوم بأخذ الخاصّية و رسالة الخطأ كتعابير. ترد وسيلة errors.full_messages (أو مكافئاتها errors.to_a ) برسالة الخطأ بشكل مفضّل للمستخدم ، و اسم الخاصّية مكبّرا و مضافًا على بداية كل رسالة ، كما يظهر في الأمثلة بالأسفل. class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, "cannot contain the characters !@#%*()_-+=") end end person = Person.create(name: "!@#") person.errors[:name] # => ["cannot contain the characters !@#%*()_-+="] person.errors.full_messages # => ["Name cannot contain the characters !@#%*()_-+="] أن ترفق رسالة في بداية مصفوفة errors.messages لخاصّية ما ، مكافيء لأن تستخدم errors#add . class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.messages[:name] << "cannot contain the characters !@#%*()_-+=" end end person = Person.create(name: "!@#") person.errors[:name] # => ["cannot contain the characters !@#%*()_-+="] person.errors.to_a # => ["Name cannot contain the characters !@#%*()_-+="] 7.4 تفاصيل الأخطاء errors.details يمكنك تحديد نوع محقّق جدول تقطيع تفاصيل الخطأ المُعاد التقطيع باستخدام وسيلة errors.add. class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, :invalid_characters) end end person = Person.create(name: "!@#") person.errors.details[:name] # => [{error: :invalid_characters}] لكي تحسّن تفاصيل الأخطاء ، لتحتوي مجموعة الحروف غير المسموح بها على سبيل المثال ، يمكنك تمرير مفاتيح إضافيّة إلى errors.add. class Person < ApplicationRecord def a_method_used_for_validation_purposes errors.add(:name, :invalid_characters, not_allowed: "!@#%*()_-+=") end end person = Person.create(name: "!@#") person.errors.details[:name] # => [{error: :invalid_characters, not_allowed: "!@#%*()_-+="}] كل محقّقات Rails المدمجة تزيد جدول تقطيع التفاصيل بنوع محقّق متناظر. 7.5 قاعدة الأخطاء errors [ :base] يمكنك إضافة رسائلك أخطاء مرتبطة بحالة الكائن ككل بدلًا من كونها مرتبطة بخاصّية مُعيّنة. يمكنك أيضًا استخدام تلك الوسيلة عندما تريد أن تقول أن الكائن غير صالح للاستخدام ، بغض النظر عن قيم خصائصه. بما أن errors[ :base] مصفوفة ، يمكنك ببساطة إضافة متسلسلة نصّية إليها و سوف تُستَخدَم كَرسالة خطأ. class Person < ApplicationRecord def a_method_used_for_validation_purposes errors[:base] << "This person is invalid because ..." end end 7.6 محو الأخطاء errors.clear تُستخدم وسيلة clear عندما تريد أن تمسح كل رسائل الخطأ في مجموعة الأخطاء errorscollection . بالطبع مناداة errors.clear لكائن غير صالح لن يجعله ساريًا أو صالحًا للاستخدام. مجموعة الأخطاء سوف تُفرّغ ، لكن المرة القادمة التي تستدعي فيها valid? أو أي وسيلة تحاول أن تحفظ الكائن في قاعدة البيّانات ، سوف تعمل التحقيقات مجّددًا. لو فشل أيّ من التحقيقات سوف تُملأ مجموعة الأخطاء مجددًا. class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end person = Person.new person.valid? # => false person.errors[:name] # => ["can't be blank", "is too short (minimum is 3 characters)"] person.errors.clear person.errors.empty? # => true person.save # => false person.errors[:name] # => ["can't be blank", "is too short (minimum is 3 characters)"] 7.7 حجم الأخطاء errors.size ترد وسيلة size بالعدد الكلي لرسائل الأخطاء للكائن. class Person < ApplicationRecord validates :name, presence: true, length: { minimum: 3 } end person = Person.new person.valid? # => false person.errors.size # => 2 person = Person.new(name: "Andrea", email: "andrea@example.com") person.valid? # => true person.errors.size # => 0 8 تقديم أخطاء التحقيق للعرض Displaying Validation Errors in Views بمجرّد إنشائك نموذجًا و إضافة تحقيقات ، لو كان النموذج مصنوع بواسطة شكل المواقع ، من المحتمل أن تريد عرض رسالة عند فشَل أحد التحقيقات. لأن كل تطبيق يعالج هذا النوع من الأشياء بطريقة مختلفة ، لا يتضمّن Rails أي view helpers لتساعدك على توليد تلك الرسائل بصورة مباشرة. مع ذلك ، بسبب فرط الوسائل التي يعطيك إيّاهاRails لكي تتعامل مع التحقيقات بشكل عام ؛ تكون العملية سهلة جدّا لإنشاء ما يخصّك منها. بالاضافة إلى ذلك ، عند إنتاج هيكل رئيسي مساعد ، سوف يضع Rails بعض ERB إلى _form.html.erb الذي تنتجه والذي يعرض قائمة بكل الأخطاء في النموذج. بافتراض أن لدينا نموذج تم حفظه في متغيّر باسم @article ، سيبدو كالتالي: <% if @article.errors.any? %> <div id="error_explanation"> <h2><%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved:</h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> علاوةً على ذلك ، إذا استخدمت تصميم Rails من المساعدين لتولّد تصميماتك/نماذجك ، عندما يحدث خطأ تحقيق في الحقل سوف تنتج إضافي بالقرب من المدخل. <div class="field_with_errors"> <input id="article_title" name="article[title]" size="30" type="text" value=""> </div>` يمكنك حين ذاك تشكيل ال div كما تريد. الهيكل الافتراضى الذي ينتجه Rails على سبيل المثال يضيف قاعدة ال CSS هذِهِ. .field_with_errors { padding: 2px; background-color: red; display: table; } هذا يعني أنّ أي حقل به خطأ ينتهي به الحال بإطار أحمر بعرض 2 بكسل. المصدر: توثيقات Ruby on Rails.
  2. في الدرسين السابقين ألقينا نظرة عامة حول التحقيقات في Active Record وتعرّفنا على مساعدات التحقيقات وسنتابع في هذا الدرس تعلم الخيارات الشائعة للتحقيقات وأنواع التحقيقات. .3 خيارات تحقيق شائعة common Validation Options هذه خيارات تحقيق شائعة 3.1 اسمح بمجموعة خالية allow_nil خيار allow_nil يتجاوز التحقيقات عندما تكون القيمة التي يجري عليها التحقيق nil. class Coffee < ApplicationRecord validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" }, allow_nil: true end لكل الخيارات لمضمون الرسالة من فضلك اقرأ الفقرة (3.3 أمر الإرسال :message). 3.2 اسمح بالفراغ :allow_blank خيار :allow_blank مماثل لخيار :allow_nil . الخيار سوف يتجاوز التحقيقات إذا كانت القيمة blank? (فراغ). مثل مجموعة أو سلسلة فارغة على سبيل المثال. class Topic < ApplicationRecord validates :title, length: { is: 5 }, allow_blank: true end Topic.create(title: "").valid? # => true Topic.create(title: nil).valid? # => true 3.3 أمر الإرسال :message كما رأيت مسبقًا ، خيار :message يسمح لك بتحديد الرسالة التي ستضاف إلى مجموعة الأخطاء عند فشل التحقيق. عندما لا يُستخدم هذا الخيار ، سيقوم Active Record باستخدام الوضع الافتراضي لرسائل الخطأ لكل مساعد تحقيق. يقبل خيار :message أي string أو proc (proc هو قالب من الكود الذي يتم إضافته أو قيده لمجموعة من المتغيّرات المحلّية ، و عندما يضاف يمكن أن يتم استدعاء هذا القالب في أكثر من سياق و يزال ويمكنه الوصول لتلك المتغيرات) قيمة رسالة سلسلة نصّية String :message يمكن –اختياريًا- أن تحتوي على أي أو كلّا من %{value} و %{attribute} و %{model} ، و التي سيتم تبديلها تلقائيّا عند فشل التحقيق. يتم هذا التغيير باستخدام I18n gem ، وماسك المكان يجب أن يتطابق تمامًا ، لا يُسمح بالمساحات. قيمة proc :message تُعطى تعبيرين ، الكائن الذي يتم التحقق منه ، و جدول تقطيع بأزواج key-value و هم :model و :attribute و :value . class Person < ApplicationRecord # Hard-coded message validates :name, presence: { message: "must be given please" } # Message with dynamic attribute value. %{value} will be replaced with # the actual value of the attribute. %{attribute} and %{model} also # available. validates :age, numericality: { message: "%{value} seems wrong" } # Proc validates :username, uniqueness: { # object = person object being validated # data = { model: "Person", attribute: "Username", value: <username> } message: ->(object, data) do "Hey #{object.name}!, #{data[:value]} is taken already! Try again #{Time.zone.tomorrow}" end } 3.4 على :on خيار :on يدعك تحدد متى ينبغي أن يجرى التحقيق. السلوك الافتراضي لكل مساعدين التحقيق المدمجين أن تجري عند الحفظ (عندما تكون تنشىء سجل جديد و عندما تقوم بتحديثه). إذا أردت تغير ذلك يمكنك استخدام on: :create لإجراء التحقيق فقط عند إنشاء سجل جديد ، أو on: :update لإجرائه عندما يتم تحديث السجل فقط. class Person < ApplicationRecord # it will be possible to update email with a duplicated value validates :email, uniqueness: true, on: :create # it will be possible to create the record with a non-numerical age validates :age, numericality: true, on: :update # the default (validates on both create and update) validates :name, presence: true end يمكنك أيضًا استخدام on: لتحديد سياق مخصّص. يحتاج السياق المخصص إلى تنشيط بشكل صريح من خلال إرسال اسمه إلى valid? أو invalid? أو save. class Person < ApplicationRecord validates :email, uniqueness: true, on: :account_setup validates :age, numericality: true, on: :account_setup end person = Person.new .person.valid? (:account_setup) يستثنى كلا التحقيقين بدون حفظ النموذج. و person.save(context: :account_setup) يتحقق من الشخص في سياق account_setup قبل الحفظ. على منشّطات صريحة ، يتم التحقق من النموذج بمحققات تابعة لهذا السياق فقط و محققات بدون سياق. 4 تحقيقات صارمة Strict Validations يمكنك أيضًا اختيار محققات لتكون مشدّدة و تنشّط ActiveModel : :StrictValidationFailed عندما يكون الكائن غير ساري. class Person < ApplicationRecord validates :name, presence: { strict: true } end Person.new.valid? # => ActiveModel::StrictValidationFailed: Name can't be blank يوجد أيضًا امكانية لعمل استثناء مخصّص على خيار :strict . class Person < ApplicationRecord validates :token, presence: true, uniqueness: true, strict: TokenGenerationException end Person.new.valid? # => TokenGenerationException: Token can't be blank 5 التحقيق المشروط conditional validation في بعض الأوقات سيبدو من المنطقي أن يتم التحقق من كائن فقط عندما تُوفى معايير فلترة معيّنة. يمكنك عمل ذلك باستخدام خيارات :if و :unless ، التي يمكن أن تأخذ رمز ، سلسلة نصّية ، أو proc. يمكنك استخدام خيار :if عندما تريد أن تحدد متى ينبغى أن يجرى التحقيق. إذا كنت تريد أن تحدد متى لا ينبغي أن يجري التحقيق إذن استخدم خيار :unless 5.1 استخدام رمز مع إذا و إذا لم Using a Sympol with :if and :unless يمكنك مصادقة خيارات :if و :unless مع رمز تناظر مع اسم الوسيلة التي سوف تُستدعى قبل حدوث التحقيق مباشرةً. هذا هو أكثر الخيارات الشائعة استخدامًا. class Order < ApplicationRecord validates :card_number, presence: true, if: :paid_with_card? def paid_with_card? payment_type == "card" end end 5.2 استخدام بروك مع إذا و إذا لم Using a Proc with :if and :unless أخيرًا يمكن ربط :if و :unless مع كائن proc ، الذي سيتم استدعاؤه. استخدام Proc object يعطيك القدرة على كتابة شرط داخلي بدلًا من وسيلة منفصلة. هذا الخيار الأفضل لها فالاستخدام مع برامج السطر الواحد (ادخال نصّي إلى ال command-line الخاص بنظم تشغيل تقوم بوظائف ما بسطر واحد من الكود) class Account < ApplicationRecord validates :password, confirmation: true, unless: Proc.new { |a| a.password.blank? } end 5.3 تجميع التحقيقات الشرطيّة Grouping Conditional Validations في بعض الأوقات يكون من المفيد أن يستخدم تحقيقات متعددة نفس الشرط. يمكن الوصول لذلك بسهولة من خلال with_options. class User < ApplicationRecord with_options if: :is_admin? do |admin| admin.validates :password, length: { minimum: 10 } admin.validates :email, presence: true end end كل التحقيقات بداخل قالب with_options سيكون قد تجاوز تلقائيّا بالفعل شرط if: :is_admin? . 5.4 ضم/دمج شروط التصديق Combining Validation Conditions من ناحية أخرى ، عندما يحدد شروط متعددة إذا كان التحقيق ينبغي أن يجري أم لا ، يُمكن استخدام مصفوفة. إضافة إلى ذلك يمكنك تطبيق كلا من :if و :unless على نفس التحقيق. class Computer < ApplicationRecord validates :mouse, presence: true, if: ["market.retail?", :desktop?], unless: Proc.new { |c| c.trackpad.present? } end يجري التحقيق فقط عندما يكون شروط :if محققة (قيمتها ture) ، و كل شروط :unless غير محقّقة. سنتابع في الدرس القادم والأخير ما بقي من هذا الدليل التعليمي حول تحقيقات Active Record. المصدر: توثيقات Ruby on Rails.
  3. في الدرس السابق ألقينا نظرة عامة حول التحقيقات في Active Record وسنتابع في هذا الدرس تعلم مساعدات التحقيقات 2 مساعدات التحقيقات validation helpers يعرض Active Record العديد من مساعدات تحقيقات المعرفة مسبقًا التي يمكنك استخدامها مباشرة داخل تعريفات فئتك. تدعم تلك المساعدات قواعد تحقيقات شائعة. فى كل مرة يفشل تحقيق ، تضاف رسالة خطأ الى مجموعة أخطاء الكائن ، و ترتبط تلك الرسالة بالخاصية التي يتم التحقق منها. يقبل كل مساعد رقم اعتباطي من أسماء الخواص ، لذلك يمكنك إضافة نفس نوع التحقيق للعديد من الخواص بسطر كود واحد. جميعم يقبل خيارات :on و :message الاثنين يحددان متى يجب أن يتم اجراء التحقيق ، و أي رسالة يجب إضافتها إلى مجموعة الأخطاء فى حال فشلها ، على الترتيب. خيار ال : on يأخذ القيم :create (أنشىء) أو :update (حدّث). هناك رسالة خطأ افتراضية لكل واحد من مساعدات التحقيق. تُستَخدم تلك الرسائل عندما لا يكون خيار : message محددًا. فلنأخذ نظرة على كل واحد من مساعدات التحقيق. 2.1 القبول acceptance تتأكد هذه الطريقة اذا ما كان الـ checkbox فى واجهة تشغيل المستخدم معلّمًا عندما يتم إرسال أي نموذج. يتم استخدام هذه الطريقة غالبًا عندما يكون المستخدم بحاجة لقبول شروطك لتقديم الخدمة ، يؤكد على قراءة نص معيّن ، أو أي مفهوم مشابه. class Person < ApplicationRecord validates :terms_of_service, acceptance: true end يجري هذا الفحص فقط إذا كانت شروط العمل ليست nil. رسالة الخطأ الافتراضية لهذا المساعد هي “must be acceptd” أي يجب أن تقبل. يمكن أيضًا تجاوز الرسالة المخصصة من خلال خيار الرسالة message. class Person < ApplicationRecord validates :terms_of_service, acceptance: { message: 'must be abided' } end يمكن أيضًا أن تستقبل خيار : accept التي تحدد القيم المسموح بها لأن تعتبر مقبولة. إنها تعود كما هو افتراضي إلى [‘1’ , true] و يمكن أن تتغير بسهولة. class Person < ApplicationRecord validates :terms_of_service, acceptance: { accept: 'yes' } validates :eula, acceptance: { accept: ['TRUE', 'accepted'] } end هذا التحقيق مخصص جدًا لتطبيقات المواقع و هذا “القبول” acceptance لا يحتاج إلى أن يسجّل في أي مكان بقاعدة البيانات. إذا لم يكن لديك مجال له ، سوف ينشىء المساعد خاصية افتراضية. إذا كان لا يوجد مجال في قاعدة بياناتك يجب أن يكون خيار القبول مفعّلًا أو يتضمن true وإلا لن يجري التحقيق. 2.2 validates.associated مرتبط بالتحقيق يجب أن تستخدم هذا المساعد عندما يكون لنموذجك ارتباطات بنماذج أخرى و هم أيضًا بحاجة إلى أن يتم التحقق منهم. عندما تحاول حفظ كائن ، valid? سيتم استدعائها لكل واحد من الكائنات المرتبطة. class Library < ApplicationRecord has_many :books validates_associated :books end هذا التحقيق سوف يعمل مع كل أنواع الارتباطات. رسالة الخطأ الافتراضى لـ validates_associated هي “is invalid” أي غير صالح. لاحظ أن كل associated object لن يحتوي على مجموعة أخطائه ، الأخطاء لا تتصاعد إلى نموذج الاستدعاء. 2.3 التأكيد confirmation يجب أن تستخدم هذا المساعد عندما يكون لديك حقول نصوص التي يجب أن تستقبل نفس المحتوى بالضبط. على سبيل المثال من الممكن أن تكون تريد التأكيد على عنوان بريد إلكتروني أو كلمة مرور. هذا التحقيق ينشىء خاصية افتراضية بنفس اسم الحقل الذي يجب أن يتم التأكيد عليه بـ”_confirmation” (تأكيد) مُلحق. class Person < ApplicationRecord validates :email, confirmation: true end فى قالب العرض خاصتك يمكن أن تستخدم شيئًا مثل: <%= text_field :person, :email %> <%= text_field :person, :email_confirmation %> هذا الفحص يجري فقط إذا كان email_confirmation ليس nil. لكي تطلب معلومات تأكد من إضافة presence check لخاصية التأكيد: class Person < ApplicationRecord validates :email, confirmation: true validates :email_confirmation, presence: true end يوجد خيار case_sensitive الذي يمكنك استخدامه لتحدد إذا ما كان من قيود التأكيد أن يكون مستشعرًا لحالة الحروف أم لا (أي يفرق بين الحروف الـ capital و الـ small). والخيار الافتراضي له هو true. class Person < ApplicationRecord validates :email, confirmation: { case_sensitive: false } end رسالة الخطأ الافتراضية لهذا المساعد هي “doesn’t match confirmation” أي لا يتوافق مع التأكيد. 2.4 استثناء exclusion هذا المساعد يصدّق أن قيم الخواص ليست متضمّنة فى مجموعة معطاة. في الحقيقة ، تلك المجموعة يمكن أن تكون أي كائن غير قابل للعد. class Account < ApplicationRecord validates :subdomain, exclusion: { in: %w(www us ca jp), message: "%{value} is reserved." } end يمتلك مساعد الاستثناء خيار : in الذي يستقبل مجموعة من القيم التي لن تقبل الخصائص المتحقق منها. خاصية : in لها اسم آخر متعارف عليه هو:within و الذي يمكن استخدامه لنفس الوظيفة. هذا المثال يستخدم خيار : message ليعرض كيف يمكن تضمين قيمة الخصّيصة. من أجل خيارات مفصّلة/كاملة لمتغير الرسالة. رسالة الخطأ الافتراضيّة هى “is reversed” 2.5 الشكل/التصميم format هذا المساعد يتحقق من قيم الخواص باختبار اذا ما كانوا تطابق تعبير اعتيادي معطى ، الذي يتم تحديده باستخدام خيار :with . class Product < ApplicationRecord validates :legacy_code, format: { with: /\A[a-zA-Z]+\z/, message: "only allows letters" } end بدلًا من ذلك يمكنك اختيار ألا تطابق الخواص المحددة expression معين باستخدام خيار :without . رسالة الخطأ الافتراضية هى “is invalid” . 2.6 التضمين inclusion هذا المساعد يتحقق أن قيم الخواص متضمنة فى مجموعة معينة. هذه المجموعة يمكن أن تكون أي كائن غير معدود. class Coffee < ApplicationRecord validates :size, inclusion: { in: %w(small medium large), message: "%{value} is not a valid size" } end مساعد التضمين inclusion helper لديه خيار:in الذي يستقبل مجموعة من القيم التي ستكون مقبولة. خيار: in لديه اسم آخر هو :within الذي يمكن استخدامه بدلًا منه لنفس الوظيفة. يستخدم المثال السابق خيار الـ :message ليبين كيف يمكن تضمين قيمة الخصّيصة. رسالة الخطأ الافتراضية لهذا المساعد هي “is not included in the list”. 2.7 الطول هذا المساعد يتحقق من طول قيم الخصائص. إنه يدعم خيارات مختلفة حتى يتسنّى للمستخدم تحديد قيود الطول بطرق مختلفة. class Person < ApplicationRecord validates :name, length: { minimum: 2 } validates :bio, length: { maximum: 500 } validates :password, length: { in: 6..20 } validates :registration_number, length: { is: 6 } end خيارات قيود الطول المتاحة هي: :minimum (أقل حد) الخاصية لا يمكن أن تكون أقل من الطول المحدد :maximum – (أقصى حد) الخاصية لا يمكن أن تكون أكثر من الطول المحدد. :in (or :within) (في حدود) طول الخاصية يجب أن يكون متضمن في أبعاد معيّنة. قيمة هذا الخيار يجب أن يكون نطاق/مدى. :is (يساوي) طول الخاصية يجب أن يكون مساويًا للقيمة المعطاه. رسالة الخطأ الافتراضيّة تعتمد على نوع تحقيق الطول المُجرى. يمكنك تخصيص هذه الرسائل باستخدام خيارات :wrong_length(طول خطأ) و :too_long (طويل جدًا) و :too_short (قصير جدًا) ، و %{count} كماسك للمكان للرقم المناظر لقيد الطول المُستخدم. يمكنك أيضًا استخدام خيار :message لتحدد رسالة الخطأ. class Person < ApplicationRecord validates :bio, length: { maximum: 1000, too_long: "%{count} characters is the maximum allowed" } end لاحظ أن رسائل الأخطاء هي جمع (على سبيل المثال “قصير جدًا) الحد الأدنى هو %{count} أحرف)”). لهذا السبب عندما يكون الحد الأدنى هو 1 يجب أن توفر رسالة مخصصة أو استخدم presence : true بدلًا من ذلك. عندما يمتلك :in أو :within حد أدنى 1 ينبغى عليك إما توفير رسالة خطأ مخصصة أو استدعاء presence طبقًا لأولوية الطول. 2.8 العددية numericality هذا المساعد يتحقق أن خواصّك بها قيم عددية فقط. افتراضيّا ، سوف يقوم بالتحقق من وجود رقم صحيح integer أو عدد عشري floating point number. لتحدد السماح بالأرقام الصحيحة فقط اضبط :only_integer على true. إذا قمت بضبط :only_integer على true ، ستقوم باستخدام: /\A[+-]?\d+\z/ عبارة اعتيادية للتحقق من قيمة الخصيصة. فيما عدا ذلك ستقوم بتحويل القيمة الى رقم باستخدام float. class Player < ApplicationRecord validates :points, numericality: true validates :games_played, numericality: { only_integer: true } end بجانب:only_integer هذا المساعد يقبل أيضًا هذه الخيارات لإضافة قيود على القيم المقبولة: greater_than : تحديد القيمة الصُغرى للقيمة المُضافة greater_than_or_equal_to : تحديد القيمة الصُغرى مع إمكانية المساواة equal_to : القيمة المُضافة يجب أن تساوي less_than : تحديد القيمة الكُبرى للقيمة المضافة less_than_or_equal_to : تحديد القيمة الكُبرى مع إمكانية المساواة other_than : القيمة المُضافة يجب ألّا تساوي تلك القيمة Odd : القيمة المضافة يجب أن تكون فردية Even : القيمة المضافة يجب أن تكون زوجية رسالة الخطأ الافتراضية هى “is not a number” (ليس رقمًا). 2.9 وجود presence هذا المساعد يتحقق أن الخصائص المحددة ليست فارغة. إنها تستخدم طريقة blank? لتكتشف إذا كانت القيمة إما nil أو سلسلة فارغة blank string – و التي تكون سلسلة فارغة أو تتكون من مساحة. class Person < ApplicationRecord validates :name, :login, :email, presence: true end إذا أردت أن تتأكد أن الارتباطات موجودة سوف تحتاج أن تختبر إذا ما كان الكائن نفسه موجودًا ، و ليس المفتاح الخارجي المستخدم لتنظيم الارتباط. class LineItem < ApplicationRecord belongs_to :order validates :order, presence: true end يجب أن تحدد خيار :inverse للرابطة حتى تتحقق من السجلّات المرتبطة التي يجب أن تكون موجودة. class Order < ApplicationRecord has_many :line_items, inverse_of: :order end إذا تحققت من وجود كائن من خلال علاقة has_one أو has_many سوف يفحص إذا ما كان الكائن ليس blank? (فارغ) ولا marked_for_destruction (محدد للمحو) بما أن false.blank? صحيح ، ينبغى أن تستخدم أحد التحقيقات التالية إذا أردت التحقق من وجود حقل Boolean: validates :boolean_field_name, inclusion: { in: [true, false] } validates :boolean_field_name, exclusion: { in: [nil] } باستخدام أحد هذه التحقيقات سوف تتأكد أن القيمة لن تكون nil ، مما سينتج عنه قيمة NULL فى أغلب الحالات. 2.10 الغياب absence هذا المساعد يتحقق من أن الخصائص المحددة غائبة. إنها تستخدم وسيلة present? لتكتشف إذا ما كانت القيمة ليست nil أو balnk string class Person < ApplicationRecord validates :name, :login, :email, absence: true end إذا أردت التأكد أن التصادق غائب ، سوف تحتاج أن تختبر ما إذا كان الكائن نفسه غائبا أم المفتاح الخارجي المستخدم لتنظيم الارتباط. class LineItem < ApplicationRecord belongs_to :order validates :order, absence: true end حتى تتحقق من السجلات المتصادقة التي يلزم غيابها يجب أن تحدد خيار :inverse_of للمصادقة. class Order < ApplicationRecord has_many :line_items, inverse_of: :order end إذا تحققت من غياب كائن من خلال علاقة has_one أو has_many ، سوف تفحص إذا ما كان الكائن ليس present? أو marked_for_destruction? مردودا كـ false. لو أردت التحقق من غياب حقل Boolean ينبغي أن تستخدم validates :field_name, exclusion: {in: [true, false] }. رسالة الخطأ الافتراضية هى “must be blank”. أى يجب أن يكون فارغًا. 2.11 التفرّد/التميّز uniqueness هذا المساعد يتحقق أن قيمة الخصيصة فريدة قبل حفظ الكائن مباشرة. إنها لا تنشىء قيد تفرّد uniqueness constraint في قاعدة البيانات ، لذلك من الممكن أن ينشىء قاعدتي بيانات مختلفتين سجلين مختلفين بنفس القيمة لعمود كنت تقصد جعله فريدًا. حتى تتجنّب ذلك يجب أن تنشىء مؤشّر متفرّد على هذا العمود في قاعدة بياناتك. class Account < ApplicationRecord validates :email, uniqueness: true end التحقق يحدث بإجراء SQL query في جدول الوسائل ، بحثًا عن سجل موجود بنفس القيمة التي في الخاصية. يوجد خيار :scope الذي يمكن استخدامه لتحديد خاصية أو أكثر تستخدم لتحديد فحص التفرّد. class Holiday < ApplicationRecord validates :name, uniqueness: { scope: :year, message: "should happen once per year" } end إذا كنت تأمل فى إنشاء قيود في قاعدة البيانات لمنع أي انتهاك لتحقيق التفرّد باستخدام خيار :scope ، فعليك إنشاء فهرس فريد لكلا العمودين في قاعدة بياناتك. انظر the SQL manual لتفاصيل أكثر عن فهارس العواميد المتعددة أو the PostgresSQL manual لأمثلة على قيود فريدة تنطبق على مجموعة من الأعمدة. يوجد أيضًا خيار :case_sensitive الذي يمكنك استخدامه لتحديد ما إذا كان قيد التفرّد سيكون حساسًا لحالة الأحرف أم لا. الضبط الافتراضي للخيار يكون ساري/صحيح true. class Person < ApplicationRecord validates :name, uniqueness: { case_sensitive: false } end رسالة الخطأ الافتراضية هي “has already been taken”. أي تم أخده بالفعل. 2.12 يتحقق بـ validates_with هذا المساعد ينقل السجل إلى فئة مختلفة من التصديق/التحقيق. class GoodnessValidator < ActiveModel::Validator def validate(record) if record.first_name == "Evil" record.errors[:base] << "This person is evil" end end end class Person < ApplicationRecord validates_with GoodnessValidator end يأخذ مساعد validates_with فئة أو قائمة من الفئات لاستخدامها للتحقيق. لا يوجد رسالة افتراضية لرسائل الخطأ لـ validates_with. يجب عليك أن تضيف الأخطاء إلى مجموعة أخطاء السجل في فئة المحقق يدويًّا. لكي تنفّذ وسيلة التحقيق يجب أن تعرّف معامل السجل ، و الذي هو السجل الذي سيتم التحقق منه. على غرار باقي التحقيقات validates_with تأخذ خيارات :if و :unless و :on . إذا جرّبت أي خيار آخر سيقوم بإرسال تلك الخيارات إلى فئة المتحقق كخيارات متاحة. class GoodnessValidator < ActiveModel::Validator def validate(record) if options[:fields].any?{|field| record.send(field) == "Evil" } record.errors[:base] << "This person is evil" end end end class Person < ApplicationRecord validates_with GoodnessValidator, fields: [:first_name, :last_name] end لاحظ أن المتحقق سوف يبدأ مرة واحدة فقط في دائرة عمر التطبيق ، و ليس لكل إجراء تحققي ؛ لذلك كن حذرًا عند استخدام متغيرات مقترحة/تجريبية بداخله. لو كان متحققك معقّد كفاية لدرجة أنك تريد متغيرات instance يمكنك استخدام plain old Ruby object بسهولة بدلاً من ذلك: class Person < ApplicationRecord validate do |person| GoodnessValidator.new(person).validate end end class GoodnessValidator def initialize(person) @person = person end def validate if some_complex_condition_involving_ivars_and_private_methods? @person.errors[:base] << "This person is evil" end end # ... End 2.13 تحقق من الكل validates_each هذا المساعد يتحقق من الخصائص مقابل block. إنها لا تمتلك وظيفة تحقيق معينة ، يجب أن تنشىء واحدة باستخدام block و كل خاصية تمر إلى validates_each سوف تُختبر في مقابلها. في المثال التالي لا نريد الأسماء و أسماء العائلات أن تبدأ بحروف صغيرة. class Person < ApplicationRecord validates_each :name, :surname do |record, attr, value| record.errors.add(attr, 'must start with upper case') if value =~ /\A[[:lower:]]/ end end الـ block يستقبل السجل و اسم الخاصية و قيمة الخاصية. يمكنك فعل أي شىء ، مثل الكشف عن البيانات الصالحة داخل الـ block. إذا فشلت تحقيقاتك ينبغي عليك إضافة رسالة خطأ إلى النموذج ؛ و من ثم جعله غير ساري. سنتابع في الدروس القادمة بقية هذا الدليل التعليمي حول Active Record Validations. المصدر: توثيقات Ruby on Rails.
  4. يوضح لك هذا الدليل كيفية التأكد من صحة وضع الكائنات Objects قبل دخولها فى قاعدة البيانات ، باستخدام خاصية تصديقات Active Record. 1 نظرة عامة على التصديقات مثال لعملية تصديق بسيطة : class Person < ApplicationRecord validates :name, presence: true end Person.create(name: "John Doe").valid? # => true Person.create(name: nil).valid? # => false كما ترى في المثال ، يُعلِمُنا استخدام خاصية التصديق بأن ” Person ” غير ساري بدون خاصية الإسم. وكذلك Person الآخر لن يتم تثبيته فى قاعدة البيانات. قبل التعمق أكثر في التفاصيل ، دعنا نتكلم أولا عن كيفية ملائمة التصديقات في الصورة الكبيرة لتطبيقك. 1.1لماذا نستخدم التصديقات؟ تُستخدم التصديقات/التحقيقات للتأكد من أن البيانات الصالحة للاستخدام وحدها التي سيتم حفظها فى قاعدة البيانات. على سبيل المثال: يمكن أن يكون مهم لتطبيقك ضمان إدخال كل مستخدم لعنوان بريد إلكتروني و عنوان بريدي صالح للاستخدام. التحقيقات التي تكون على المستوى النموذجي Model-level Validations هى الطريقة الأمثل لضمان حفظ البيانات السارية وحدها بقاعدة بياناتك. إنها قابلة للتشغيل المتبادل على قواعد البيانات ، حيث لايمكن للمستخدم تجاوزها أو التحايل عليها من أي مستخدم ، و مناسبة للاختبار و التعامل المستمر. Rails تجعلها سهلة الاستخدام ، توفّر مساعد مدمج للاستخدامات الشائعة ، و تسمح لك بصناعة طرق التحقق الخاصة بك أيضًا. هناك العديد من الطرق للتحقق من صحة البيانات قبل حفظها فى قاعدة البيانات، بما فى ذلك بعض القيود المرتبطة أساسًا بقاعدة البيانات، تصديقات من جانب العميل client-side validations ، و تصديقات على مستوى التحكم controller-level validation. إليك ملخّص السلبيّات و الإيجابيّات: قيود قواعد البيّانات و/أو الإجراءات المخزّنة تجعل آليّات التحقيق معتمدة على قاعدة البيّانات ، و يمكن أن تجعل الإختبار و الصيانة أكثر صعوبة. مع ذلك ، لو كانت قاعدة البيانات الخاصة بك تستخدم بواسطة تطبيقات أخرى ، فقد تكون فكرة جيدة أن تستخدم بعض القيود على مستوى قاعدة البيّانات. بالإضافة إلى ذلك، التصديقات التي تكون على مستوى قاعدة البيانات يمكن أن تتعامل بأمان مع بعض الأشياء التي يصعب تطبيقها بالطرق الأخرى (مثل التميز/التفرّد فى الجداول المستخدمة بكثرة). يمكن للتحقيقات التي تكون من جهة العميل مفيدة ، لكنها بشكل عام لا يُعتَمد عليها اذا تم استخدامها وحدها. إذا تم تنفيذها باستخدام JavaScript يمكن تجاوزها إذا كانت JavaScript غير مفعّلة فى متصفّح المستخدم. مع ذلك ، اذا تم دمجها مع تقنيّات أخرى يمكن أن تكون هذه التحقيقات طريقة مناسبة لتوفير ردود أفعال لمستخدمي موقعك. Controller-level validations يمكن أن تكون مغرية للاستعمال ، لكن في الغالب تصبح غير عمليّة و صعبة فى الاختبار و الصيانة. من الجيد أن تجعل متحكماتك صغيرة ، حيث ستجعل تطبيقك محبب للاستخدام على المدى الطويل. قم بالإختيار مما سبق فى بعض الحالات التي تراها مُناسبة. لكن رأى فريق Rails أن model-level validations هي الأكثر تناسبًا لجميع الظروف. 1.2لماذا يحدث التحقيق؟ هناك نوعان من كائنات Active Record: تلك التى تتوافق مع صف بداخل قاعدة بياناتك ، و تلك التى لا تتوافق. عندما تنشىء كائن جديد – باستخدام طريقة new على سبيل المثال - هذا الكائن لا ينتمى لقاعدة البيانات حتّى اللحظة. ما إن تقوم باستدعاء save لهذا الكائن سيتم حفظه في الجدول المناسب بقاعدة البيانات. يستخدم Active Record طريقة new_record? لتحديد إذا ما كان الكائن موجود في قاعدة البيانات أم لا. فكّر في فئة Active Record التالية: class Person < ApplicationRecord end يمكننا ملاحظة أنها تعمل بالنظر إلى ناتج rails console: $ bin/rails console >> p = Person.new(name: "John Doe") => #<Person id: nil, name: "John Doe", created_at: nil, updated_at: nil> >> p.new_record? => true >> p.save => true >> p.new_record? => false إن إنشاء و حفظ سجل جديد سوف يرسل عمليّة SQL INSERT إلى قاعدة البيانات. تحديث سجل موجود سوف يرسل عملية SQL UPDATE بدلًا من ذلك. التحقيقات تُجرى عادةً قبل إرسال هذه الأوامر إلى قاعدة البيانات. في حين فشل أي تحقيق سيتم تحديد الكائن “غير صالح” و لن ينفّذ Active Record عمليات الإدخال أو التحديث. يتجنّب هذا تخزين كائنات غير سارية في قاعدة البيانات. يمكنك أيضًا اختيار إجراء تحقيقات معينة عند إنشاء وحفظ أو تحديث كائن. الطرق التالية تُشغل التحقيقات و سوف تحفظ الكائنات في قاعدة البيانات فقط إذا كانت صالحة للاستخدام: create create! save save! update update! الأوامر التى تنتهي بـ ! bang versions ( save! على سبيل المثال) تقوم بعمل استثناء فى حالة عدم صحة السجل. الآخرون لا يفعلون ذلك. Save و update يُخرجوا false خطأً ، و create تُعيد نفس الكائن. 1.3 تخطّى التحقيقات الدوال التالية تتخطى التحقيقات و تحفظ الكائن فى قاعدة البيانات بغض النظر عن صحّته. لذلك يجب استخدامها بحذر. decrement! decrement_counter increment! increment_counter toggle! touch update_all update_attribute update_column update_columns update_counters لاحظ أن save لديها القدرة على تخطي التحقيقات إذا تم إلحاقها بالأمر validate: false. هذه الطريقة أيضًا يجب استخدامها بحرص. save(validate: false) 1.4 Valid? و invalid? >> صالح؟ و غيرصالح؟ قبل حفظ كائن في Active Record ، يجري Rails تحقيقاتك. لو كانت هذه التحقيقات تخرج أخطاء ، لا يقوم Rails بحفظ الكائن. يمكنك أيضًا إجراء هذه التحقيقات بنفسك. Valid? ينشّط تحقيقاتك و يرد بـ true (صحيح) إذا لم يكن هناك أخطاء. و false (خطأ) فيما عدا ذلك. كما رأيت بالأعلى: class Person < ApplicationRecord validates :name, presence: true end Person.create(name: "John Doe").valid? # => true Person.create(name: nil).valid? # => false بعد إجراء Active Record لتحقيقاتك، يمكن الوصول لأي خطأ من خلال وسيلة errors.messages التي ترد بمجموعة من الأخطاء. كما هي معرّفة ، الكائن صالح للاستخدام إذا كان تجمع الأخطاء هذا فارغًا بعد إجراء التحقيقات. لاحظ أن الكائن الممثل بـ new لن يبلغ عن أخطاء حتى لو كان غير صالح تقنيًّا؛ لأن التحقيقات تُجرى تلقائيّا عندما يتم حفظ الكائن ، كما هوالحال مع دوال create و save. class Person < ApplicationRecord validates :name, presence: true end >> p = Person.new # => #<Person id: nil, name: nil> >> p.errors.messages # => {} >> p.valid? # => false >> p.errors.messages # => {name:["can't be blank"]} >> p = Person.create # => #<Person id: nil, name: nil> >> p.errors.messages # => {name:["can't be blank"]} >> p.save # => false >> p.save! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank >> Person.create! # => ActiveRecord::RecordInvalid: Validation failed: Name can't be blank Invalid? هي ببساطة عكس valid?. تقوم بإجراء التحقيقات و ترد بـ true إذا وُجِدَ أي خطأ ، و false إذا لم تتواجد أيّة أخطاء. 1.5 errors[] (الأخطاء) لكي تتأكد ما اذا كانت خاصّية معينة لكائن سارية أم لا يمكنك استخدام errors [ : attribute]. تقوم بالرد بمصفوفة array بكل الأخطاء للخاصيّة. إذا لم يكن هناك أخطاء للخاصية المحددة يتم الرد بمصفوفة فارغة. تكون تلك الطريقة مفيدة بعدما تُجرى التحقيقات فقط ؛ لأنها تقوم بفحص مجموعات الأخطاء فقط ولا تنشّط التحقيقات بنفسها. إنها تختلف عن طريقة ActiveRecord : : Base#invalid? المشروحة بالأعلى ؛ لأنها لا تؤكّد صحّة الكائن ككل. إنها تقوم فقط بفحص إذا وُجد أخطاء بخاصيّة واحدة بالكائن. class Person < ApplicationRecord validates :name, presence: true end >> Person.new.errors[:name].any? # => false >> Person.create.errors[:name].any? # => true 1.6 errors.details تفاصيل الأخطاء لكي تكشف أي تحقيقات فشلت فى خاصية معيّنة يمكنك استخدام errors.details [ : attribute ]. تقوم بالرد بمصفوفة من الـ hashes مع مفتاح : error للحصول على رمز المصادقة: class Person < ApplicationRecord validates :name, presence: true end >> person = Person.new >> person.valid? >> person.errors.details[:name] # => [{error: :blank}] المصدر: توثيقات Ruby on Rails.
  5. في الدروس السابقة ألقينا نظرة عامة على تهجير Active Record وكيفية إنشائه كما وتعلمنا أوامر التهجير وسنتابع في هذا الدرس ما بقي من هذه السلسلة التعليمية حول تهجير Active Record. 4 تشغيل التهجير Running Migration Rails توفر مجموعة من مهام bin/rails لتشغيل مجموعة التهجيرات التي تريدها. إن أول مهام التهجير bin/rails التي ستستعملها سيكون غالبًا rails db:migrate. و هذا هو أبسط صور التهجير حيث يقوم بتشغيل دوال change و up لكل التهجيرات التي لم تقم بتشغيلها بعد. و سيقوم بالإغلاق إن لم يُكن لديك تهجيرات من هذا النوع. عدا ذلك سيقوم بتشغيل التهجيرات بالترتيب طبقًا لتوقيته. لاحظ أن تشغيل أمر db:migrate سيقوم بتشغيل الأمر db:schema:dump و هذا سوف يقوم بتحديث ملف db/schema.rb ليوافق تركيب قاعدة بياناتك. إذا قُمت بتحديد نُسخة versionمعينة، فإن Active Record سيقوم بعمل التهجيرات اللازمة (باستخدام دوال change و up و down) حتى يصل للنسخة المرغوبة. يُعبر عن النسخة باستخدام أرقام توضع في إسم ملف التهجير، فإذا أردت أن تقوم بالتهجير لنُسخة 20080906120000 قُم بتشغيل: $ bin/rails db:migrate VERSION=20080906120000 إذا كانت النُسخة المرغوبة تحمل رقم أعلى من الرقم السابق فإن التهجير سيقوم بتشغيل دوال change أو up. و يقوم بعمل التهجيرات حتى يصل إلى رقم النُسخة المرغوبة. أما إذا كانت النسخة المرغوبة تحمل رقمًا أعلى فإن التهجير سيقوم بتشغيل دالة down حتى تصل إلى رقم النُسخة، لكنه لن يقوم بعمل تهجير لها(لأن ذلك سيؤدي إلى نُسخة أقل من المرغوبة). 4.1 العودة للوراء باستخدام rollback سيتحتم عليك أحيانًا العودة بالتهجير للوراء (لاحظ الفرق بينه و بين العكس). مثال: إذا أردت أن تقوم بتصحيح خطأ قُمت به، فبدلًا من تتبع رقم النُسخة المرتبطة بذلك التهجير، يُمكنك تشغيل هذا الكود: $ bin/rails db:rollback إن أمر rollback سيقوم بعكس دالة change أو تشغيل دالة down. أما إذا أردت أن تعود لأكثر من تهجير يُمكنك تحديد عدد المرات التي ستعمل فيها الدالة rollback عن طريق STEP. مثال: $ bin/rails db:rollback STEP=3 هذا سوف يعكس 3 تهجيرات. إن أمر db:migrate:redo يُعتبر إختصار لأمر rollback و لكنه سيعود بك لنقطة البداية مُجددًا. و يُمكنك تعيين عدد الخطوات به أيضًا باستخدام STEP، مثال: $ bin/rails db:migrate:redo STEP=3 إن دالة db:migrate يُمكنها أي شيئ تقوم به أوامر bin/rails ولكنهم أكثر مُلائمة عندما لا تحتاج لتحديد النُسخة التي تعمل عليها بدقة. 4.2 تهيئة قاعدة البيانات Setup Database أمر rails db:setup سيقوم بصنع قاعدة البيانات و تحميل الإسكيما و تزويدها ببياناتها الأولية. 4.3 إعادة تهيئة قاعدة البيانات Resetting Database لإعادة التهيئة استخدم أمر rails db:reset ثم قُم باستعمال أمر التهيئة من جديد. و هذان الأمران يُمكن استبدالهما بدالة rails db:drop db:setup 4.4 تشغيل تهجيرات محددة Running Specific Migrations إذا كُنت تريد إجراء عملية تهجير محددة سواء للأمام up أو للخلف down. فيُمكنك إستخدام أمر db:migrate:up أو db:migrate:down و لكن سيتوجب عليك تحديد تعيين رقم نُسخة التهجير الذي ترغب بعمله، مثال: $ bin/rails db:migrate:up VERSION=20080906120000 في المثال السابق سيقوم Active Record بالتأكد من وجود هذا التهجير مُسبقًا أم لا. فإن لم يكن موجودًا من قبل فسيقوم بتشغيل دالة change أو دالة up. أما إذا كان موجودًا بالفعل فلن يقوم بشيء. 4.5 تشغيل التهجير في بيئات عمل مختلفة different environments تلقائيًا يتم تشغيل bin/rails db:migrate في بيئة development. ويُمكنك استعمال هذا الأمر RAILS_ENV لتحديد بيئة العمل التي ترغب بعمل التهجير عليها، في الكود التالي سنقوم بعمل التهجيرات على بيئة test: $ bin/rails db:migrate RAILS_ENV=test 4.6 تغيير ناتج (خارج – Output) التهجير إن التهجير تلقائيًا يقوم بإخبارك بالمهام التي يفعلها و الوقت الذي قد يأخذه، فإذا قُمت باستخدام تهجير لصنع جدول أو إضافة قاموس، فإن الناتج سيكون هكذا: == CreateProducts: migrating ================================================= -- create_table(:products) -> 0.0028s == CreateProducts: migrated (0.0028s) ======================================== و هُناك العديد من الدوال المتوفرة داخل ملفات التهجير تساعد بمعرفة هذا الأمر: الدالة غرضها suppress_message يقوم بتحديد جزء من الكود block و يقوم بإخراج رسالة تحتوي على ما بهذا الكود. Say يقوم هذا الأمر بحفظ نص رسالة و تقديمها كما هي. و سيقوم مُتغير من نوع Boolean بتحديد ظهور الرسالة من عدمه say_with_time يقوم بتحديد وقت مُعين لظهور الرسالة، و إذا كان الكود المكتوب يُخرج رقم integer فإنه يُعامله على أنه عدد الصفوف المُتأثرة. على سبيل المثال، فإن هذا التهجير: class CreateProducts < ActiveRecord::Migration[5.0] def change suppress_messages do create_table :products do |t| t.string :name t.text :description t.timestamps end end say "Created a table" suppress_messages {add_index :products, :name} say "and an index!", true say_with_time 'Waiting for a while' do sleep 10 250 end end end سوف يُنتج هذه المُخرجات == CreateProducts: migrating ================================================= -- Created a table -> and an index! -- Waiting for a while -> 10.0013s -> 250 rows == CreateProducts: migrated (10.0054s) ======================================= أما إذا أردت من Active Record ألا يُخرج أي شيئ فيُمكنك استخدام أمر rails db:migrate VERBOSE=false 5 تغيير التهجيرات الموجودة مُسبقًا إذا قُمت بارتكاب خطأ ما أثناء كتابتك للتهجير، و قُمت بتشغيل التهجير. فلا يُمكنك تعديل التهجير ثًم تشغيله من جديد. لأن Rails لن تفعل شيئًا عند كتابة الأمر rails eb:migrate لأنك بالفعل قُمت بتشغيله من قبل. لذلك عليك استخدام أمر العودة rollback بكتابة bin/rails db:rollback ثُم تعديل التهجير ثُم تشغيله من جديد. بوجه عام، تعديل التهجيرات السابقة ليس أمرًا جيدًا، لأنه سيتسبب لك بالكثير من العمل، أنت و من يعملون معك على قاعدة البيانات. خصيصًا إن تم تشغيل هذا التهجير على أجهزة السيرفرات بالفعل. فبدلًا من عمل ذلك يُمكنك كتابة تهجير جديد وظيفته هي تغيير الأخطاء أو عمل التعديلات اللازمة. فإن تعديل تهجير مكتوب حديثًا أسهل من تعديل تهجير تم تشغيله على الأجهزة فعلًا. يُمكنك إستخدام أمر العاكس revert الذي تحدثنا عنه هُنا مُسبقًا. 6 إهمال الإسكيما Schema Dumping 6.1 ماهي ملفات الإسكيما؟ إن التهجيرات، ليست هي المُتحكمة بالإسكيما الخاصة بقاعدة بياناتك. إن هذا الأمر (التحكم) يعود إلى ملفات db/schema.rb أو ملف SQL. و تلك الملفات تولد من Active Record عن طريق مُعاينة قاعدة البيانات. وإن تلك الملفات ليست مُصممة ليتم التعديل عليها، بل هي تُظهر و تُمثل حالة قاعدة البيانات. ليس هُناك حاجة لعمل جزئية جديدة بتطبيقٍ ما عن طريق إعادة تشغيل جميع التهجيرات بالتطبيق. فإنه من الأسهل و الأسرع إضافة وصف تلك الجزئية للإسكيما الحالية لقاعدة البيانات. هكذا تكون قاعدة البيانات الإختبارية على سبيل المثال، بحيث يتم إهمال الملفات الحالية لقاعدة البيانات (ملف db/schema.rb و db/structre.sql) و يتم تحميلها إلى قاعدة البيانات الإختبارية test database. إن ملفات الإسكيما مُفيدة أيضًا إذا أردت أن تلقي نظرة سريعة إلى الخصائص التي تحملها كائنات Active Record. حيث أن هذه المعلومات لا توجد في كود نموذج قاعدة البيانات و أحيانًا تكون مُنتشرة بين العديد من التهجيرات، لكن المعلومات تكون جميعها موجود في ملفات الإسكيما بشكل مُنظم. 6.2 أنواع إهمال الإسكيما schema dumps هُناك طريقتين أساسيتين لهجر/إهمال إسكيما ما. هذا يكون موجودًا داخل ملف config/application.rb عن طريق إعداد config.active_record.schema_format، و من المُمكن أن يكون ملف روبي :ruby أو :sql إذا كان من نوع روبي :ruby فإنه سيبدو مثل تهجير كبير، و ستجده داخل db/schema.rb، مثال: ActiveRecord::Schema.define(version: 20080906171750) do create_table "authors", force: true do |t| t.string "name" t.datetime "created_at" t.datetime "updated_at" end create_table "products", force: true do |t| t.string "name" t.text "description" t.datetime "created_at" t.datetime "updated_at" t.string "part_number" end end في كثير من الحالات، يتم صُنع هذه الملفات عن طريق مُعاينة قاعدة البيانات و تركيبها باستعمال الدوال المُستخدمة بصُنعها مثل create_table و add-Index و غيرهم. و لأن هذا أمر يكون مُستقل بقاعدة البيانات، فيُمكن استخدامها على أي قاعدة بيانات يدعمها Active Record. ومن فوائد هذا الأمر، أنه يُمكنك توزيع بيانات تطبيق ما على العديد من قواعد البيانات. من سلبيات ملف الإسكيما db/schema.rb أنه لا يُمكنك التعبير عن جميع مُكونات قاعدة البيانات مثل: المُشغلات/مُنشطات triggers و نقاط التحقق check constraints. بينما في التهجير يُمكنك الإستعانة بسطور SQL. و الإسكيما لا يُمكنها أن تحتوي على تلك السطور. لذلك إن إحتوت قاعدتك بيانات على مثل هذه الخصائص، فيجب عليك تحويل صيغة ملف الإسكيما إلى :sql. بدلًا من إهمال استعمال إسكيما Active Record، فإنه يُمكنك إهمال تركيب/تخطيط قاعدة البيانات بإستخدام أدوات مُعينة مثل (أمر Rails db:structre:dump ) في ملف db/structre.sql. على سبيل المثال: في قواعد بيانات من نوع PostgreSQL يُمكنك إستخدام pg_dump. أما في قواعد بيانات MySQL و MariaDB فإن الملف سيظهر لك SHOW CREATE TABLE لمُختلف الجداول التي يحويها هذا الملف. 6.3 إهمال الإسكيما و التحكم بالكود المصدري source control لأن أوامر إهمال الإسكيما هي المُنحكم الرئيسي بالإسكيما الخاصة بقاعدة البيانات. لذلك يُنصح بشدة بأن تتأكد من وجودهم بلوحة تحكم المصدر الخاصة بك. إن ملف db/schema.rb يحتوي على النُسخة الحالية من قاعدة البيانات الخاصة بك. هذا يؤكد حدوث الأخطاء عند دمج العديد منها. و حل هذا الأخطاء يكون يدويًا بإبقاء النُسخة الأعلى من المدمجين. 7 Active Record و التكامل المرجعي referential integrity إن Active Record يدعي أن هُناك آلية ذكية في النماذج الخاصة بقواعد البيانات و ليس بقواعد البيانات نفسها. مثل المميزات triggers و constraints التي تضيف هذه الآلية إلى قاعدة البيانات نفسها, و لكنها ليست مُستخدمة بكثرة. التحقيقات مثل validates:foreign_key و uniqueness: true هي التي تُستخدم عن تكامل البيانات بين قواعد البيانات. فأمر :dependent في القواعد المُتصلة يسمح بتدمير الكائن المورَث عند تدمير الكائن المورِث. هذا لا يُمكن ضمان حدوثه في التكامل المرجعي بوجود تحقيقات المفاتيح الأجنبية في قاعدة البيانات. و مع ذلك فإن Active Record لا يوفر جميع الأدوات التي تعمل مُباشرةً مع هذه المميزات، لذلك فإنه يُمكنك إستخدام أمر excute لتنفيذ أوامر SQL. 8 التهجير و البيانات المرجعية seed data حتى لا ننسى أن الهدف الأساسي من خاصية التهجير و هو عمل أوامر تُعدل على الإسكيما بإستخدام أوامر ثابتة و مُتسقة. إن التهجير أيضًا يُمكن إستعماله لإضافة أو تعديل البيانات، و هذا مُفيد في قواعد البيانات الموجودة مُسبقًا التي لا يُمكن تدميرها و إعادة صُنعها. مثل تلك قاعدة البيانات الخاصة بالإنتاج: class AddInitialProducts < ActiveRecord::Migration[5.0] def up 5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") end end def down Product.delete_all end end لإضاافة بيانات أولية seed data بعد صُنع قاعدة البيانات. إن Rails لديها دالة داخلية built-in تُساعد على تسهيل تلك العملية. خصيصًا عند إعادة تحميل قواعد البيانات بشكل مُتكرر أثناء التطوير و الإختبار. يُمكنك إستخدام تلك الخاصية بكتابة أكواد ruby التي تريدها في ملف db/seeds.rb ثُم تشغيل أمر rails db:seed: 5.times do |i| Product.create(name: "Product ##{i}", description: "A product.") End و يُمكنك إستخدام تلك الخاصية لإعداد قاعدة بيانات فارغة من البداية. وبذلك نكون قد أنهينا هذه السلسلة المخصصة لتعلّم تهجير Active Record في إطار العمل روبي أون ريلز. المصدر: توثيقات Ruby on Rails.
  6. في الدرس السابق ألقينا نظرة عامة على تهجير 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. 3.5 مُعدلات الأعمدة إن مُعدلات الأعمدة Column Modifiers يُمكن أن تُطبق عند صُنع أو تغيير العواميد: limit : يقوم بتحديد أقصى مساحة للحقول من الأنواع string/text/binary/integer Precision : يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد قبل العلامة العشرية Scale : يُحدد دقة الأرقام العشرية بتحديد عدد الوحدات في الرقم الواحد بعد العلامة العشرية Polymorphic : يُضيف عامود type إلى رابطة belong_to Null : تسمح بإستخدام قيمة NULL أو عدم إستخدامها بالعامود. Default : يُتيح لك بتعيين قيمة إفتراضية بالعامود. مع مُلاحظة أنه عند إستخدامك قيمة ديناميكية (مثل التاريخ، فإنه سيتم تعيين القيمة الإفتراضية للتاريخ الذي تم صُنع التهجير عنده. Index : يُضيف فهرس للعامود Comment : يُضيف تعليق للعامود بعض المحولات adapters تدعم بعض الخيارات الإضافية: يُمكنك رؤية التوثيقات الخاصة بتلك المحولات لمعرفة المزيد عن هذا الأمر. 3.6 المفاتيح الأجنبية على الرغم من عدم إضطرارك لإضافة المفاتيح الأجنبية Foreign Keys إلا أنه يُمكنك فعل ذلك لضمان السلامة المرجعية لقاعدة البيانات. add_foreign_key :articles, :authors هذا سوف يُضيف مفتاح أجنبي جديد إلى عامود author_id في جدول articles. والمفتاح سيرمز إلى عامود id في جدول authors. أما إذا كانت أسماء الأعمدة لا يُمكن إشتقاقها من أسماء الجداول، فيُمكنك إستخدام الأوامر :column و :primary_key. إن Rails أيضًا ستقوم بتوليد إسم إفتراضي لكُل مُفتاح أجنبي، سيبدأ بـ fk_rails_ ثُم سيُتبع بعشرة حروف التي ستتولد تلقائيًا من أمر from_table و column. و يُمكنك أيضًا إستخدام :name لتعيين إسم مُختلف إذا أردت. حذف المفاتيح الأجنبية لهو أمر سهل أيضًا: # 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. سنتابع في الدرس التالي ما تبقى من هذا الدليل التعليمي حول تهجير Active Record المصدر: توثيقات Ruby on Rails.
  7. إن التهجير من أهم مزايا 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 هي سلسلة من العمليات تتم على وحدة مُفردة من قاعدة البيانات. و تكون مُستقلة تمامًا عن باقي العمليات. 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.
  8. سنتابع في هذا الدرس دليل Active Record، حيث تعلمنا في الدرس السابق ماهية Active Record، استيراد الأكواد من اللغات الأخرى والنماذج. وسنتابع في هذا الدرس بقية دليل Active Record. 4 تخطي طُرق التسمية الخاصة بـ Rails ماذا تفعل إن إحتجت أن تستعمل طريقة أخرى للتسمية غير المُتبعة بـ Rails؟ لا يوجد مُشكلة حيث يُمكنك تخطي قواعد التسمية بسهولة. إن سجل التطبيق ApplicationRecord يستلهم من Active Record ActiveRecord::Base و هذا الأمر يُعطينا العديد من الطرق التي يُمكن إستخدامها لتخطي قواعد التسمية. فيُمكنك –مثلًا- إستعمال هذا الأمر ActiveRecord::Base.table_name= لتحديد الإسم المُناسب للجدول الذي تُريد إنشائه. class Product < ApplicationRecord self.table_name = "my_products" end إذا فعلت ذلك فيجب عليك أن تعرف إسم الفئة class التي تحمل الثوابت (my_products.yml) يدويًا بإستعمال هذا الأمر set_fixture_class في تعريف الاختبار الخاص بك test definition. 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 5 قراءة و كتابة البيانات CRUD إن CRUD هي إختصار الأربع كلمات الآتية: Create, Read, Update و Delete. Active Record يقوم –تلقائيًا- بصنع الدوال التي تسمح لتطبيقٍ ما بقراءة و تعديل البيانات الموجودة داخل جداولها. 5.1 أمر Create يُمكن عمل كائنات objects في Active Record باستخدام رمز الشباك hash أو كما يُمكن تعيين خصائصها يدويًا بعد تعريفها. فإن دالة new سوف تُخرج كائن جديد. بينما دالة create سوف تُخرج كائن جديد و تقوم بحفظه في قاعدة البيانات. على سبيل المثال، بافتراض وجود نموذج model يُسمى User و خصائصه name و occupation، فإن دالة method سوف تقوم بصُنع النموذج و حفظه بقاعدة البيانات. user = User.create(name: "David", occupation: "Code Artist") بينما إستعمال دالة new سوف تقوم بصُنع الكائن object و لكن بدون حفظه user = User.new user.name = "David" user.occupation = "Code Artist" و عند كتابة user.save سوف يُحفظ الكائن في قاعدة البيانات. وبافتراض وجود block مُسبق، فإن كلاً من الأمرين creat و new سوف يقومان بإخضاع ذلك الكائن للبلوك block في البداية. user = User.new do |u| u.name = "David" u.occupation = "Code Artist" end 5.2 أمر Read إن Active Record يوفر واجهة برمجة تطبيقات قوية من أجل الولوج للبيانات الموجودة داخل قاعدة البيانات. في الأكواد التالية، سيكون هُناك عدة أمثلة للولوج إلى قواعد البيانات بإستخدام Active Record. # return a collection with all users users = User.all # return the first user user = User.first # return the first user named David david = User.find_by(name: 'David') # find all users named David who are Code Artists and sort by created_at in reverse chronological order users = User.where(name: 'David', occupation: 'Code Artist').order(created_at: :desc) 5.3 أمر Update يُمكنك إعادة التعديل على خصائص الكائن object و حفظ التغييرات في قاعدة البيانات. user = User.find_by(name: 'David') user.name = 'Dave' user.save و يوجد طريق مُختصر لعمل التحديثات أيضًا بإستخدام hash mapping. user = User.find_by(name: 'David') user.update(name: 'Dave') و هذه الطريقة مُفيدة إذا أردت أن تُحدث العديد من الخصائص في وقتٍ واحد. و لكن إذا أردت تحديث العديد من السجلات مرة واحدة، فيُمكنك إستخدام أمر update_all: User.update_all "max_login_attempts = 3, must_change_password = 'true'" 5.4 أمر Delete يُمكنك حذف أي كائن بعد تخزينه بقاعدة البيانات، باستخدام تلك الأكواد: user = User.find_by(name: 'David') user.destroy 6 التوثيق Validation إن Active Record يسمح لك بعمل توثيق لحالة نماذج البيانات (models) قبل إدخالها في قواعد البيانات. هناك العديد من الطرق لتوثيق النماذج قبل إدخالها قواعد البيانات مثل التأكد من أن قيمة المُدخل ليست فارغة و أنها غير موجودة بالفعل في قاعدة البيانات أو أنها تتبع تنسيقًا معينًا و الكثير من الأمور التي يمكن استخدامها للتوثيق. إن التوثيق أمر في غاية الأهمية عند تثبيت البيانات داخل قاعدة البيانات. لذلك فإن الدوال 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 7 دوال الإستدعاء Callbacks إن دوال الإستدعاء داخل Active Record تسمح لك بإرفاق الكود لحدث مُعين يتكرر في دورة تكرار النموذج model الخاص بك. وهذا الأمر يسمح لك بإضافة أفعال إلى نماذجك مشروطة بحدوث أحداث مُعينة. فعلى سبيل المثال: عند صُنع سجل جديد يقوم Active Record بتحديث آخر أو حذفه، إلخ. 8 التهجير Migrations إن Rails توفر لغة مُحددة المجال domain-specific لإدارة قواعد البيانات تُسمى بالتهجير. إن أوامر التهجير مُخزنة بملفات يتم إخراجها لأي قاعدة بيانات يتم دعمها من Active Record باستخدام الأمر 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 تتقفى آثر الملفات التي سُلمت لقاعدة البيانات و توفر إمكانية إستعادة تلك القاعدة rollback. لذلك فلإنشاء جدول يجب عليك كتابة الأمر في rails db:migrate و إستعادته بإستخدام db::rollback. لاحظ أن الكود المُستخدم أعلاه يُمكن إستخدامه بأي قاعدة بيانات مثل MySQL و PostgreSQL و Oracle و غيرها. من توثيقيات Ruby on Rails
  9. سنتابع في هذا الدرس من سلسلة تعليم إطار العمل Ruby on Rails حيث سنتعرف على Active Record. 1 ما هو Active Record؟ Active Record هو جزء من النمط البرمجي MVC -شرحها بأسفل المقال- و هو المسئول عن جزء البيانات. حيث إن Active Record هو الجزء المسؤول عن عرض البيانات و خوارزميتها. فيسهل Active Record صنع و إستخدام عناصر البيانات التي تتطلب مساحة دائمة في قاعدة البيانات database. إن تطبيق نمط Active Record يُعتبر نفسه وصف و جزء من الـ ORM – يوجد تعريف بالأسفل- . ** MVC- Model View Controller - هو نمط تم اعتماده كطريقة للبرمجة حيث يعتمد هذا النمط في الاساس على عزل ما هو مرأي للمستعمل (user interface) عن ما يتعلق بالبيانات(data) و طرق استخدامها، حيث ينفصل الجزء المختص بالبيانات عن الواجهة و يمكن عمل أكتر من مطور على المشروع بسلاسة و دون تعارض. من مثال المنصات التي تعمل بتلك الطريقة هي Laravel ** ORM Object- Relational- Object هو تكنيك برمجي مستخدم لتحويل البيانات بين الأنظمة غير المتوافقة عن طريق تحويل الصفوف و الأعمدة إلى كائنات بإستخدام البرمجة الشيئية. 1.1 نمط Active Record لقد عرف مارتن فويلر Active Record في كتابه Patterns of Enterprise Application Architecture وفي هذا التعريف أوضح ماهيته. في Active Record، يحمل الكائن object كلاً من البيانات الدائمة و العمليات التي ستتم عليها. Active Recordيعمل على ربط منطق الولوج إلى البيانات بالكائن بحيث يُعلم المُستخدمين كيفية إدخال و إخراج البيانات من قاعدة البيانات. 1.2 رسم العلاقات بين الكائنات Object Relational Mapping يُرمز إلى هذا المصطلح بالإختصار ORM ، وهو تقنية تربط بين الكائنات المُختصة بتطبيقٍ ما مع جداول في نظام إدارة قواعد البيانات المتصلة. بإستعمال ORM يمكن تخزين و إستخدام خصائص و علاقات الكائنات في التطبيق بدون الحاجة إلى كتابة أوامر SQL بل بطريقة مُباشرة و بإستخدام أكواد أقل. 1.3 Active Record كمنصة ORM Active Record يوفر لنا العديد من الإمكانيات، أهمها: تمثيل النماذج models و بياناتها تمثيل الروابط بين تلك النماذج تمثيل البيانات الموروثة بين نماذج البيانات المُتصلة توثيق النماذج قبل تثبيتها بقواعد البيانات تطبيق عمليات قواعد البيانات بإستخدام إسلوب البرمجة الشيئية 2 سهولة إستيراد الأكواد من اللغات الأخرى عند كتابة أحد التطبيقات بلغةٍ ما أو منصةٍ أخرى لإستعمالها في منصة ORM فإن هذه الأكواد تحتاج إلى الكثير من التهيئة configuration . و لكن هذا الأمر قد تم حله في Rails حيث ستحتاج إلى كتابة أكواد قليلة جداً لعمل التهيئة (وفي بعض الأحيان لن تحتاج إلى التهئية على الإطلاق) عند صنع نماذج Active Record. طريقة عمل هذه التهيئة تعتمد على الإستناد إلى تهيئة التطبيقات بالطريقة نفسها في معظم الأوقات بطريقة رئيسية. ومع ذلك، في بعض الأحيان ستحتاج إلى كتابة أكواد التهيئة عندما لا تتناسب التطبيقات التي تستوردها مع الطريقة الرئيسية للتهيئة في Rails. 2.1 طريقة التسمية Naming إن Active Record يستعمل قواعد تسمية تُساعد على صُنع الروابط بين النماذج و جداول قواعد البيانات. Rails ستقوم بتحويل أسماء الأصناف classes إلى صيغة الجمع لتناسب جدول قاعدة البيانات المناسب لها. على سبيل المثال، إذا كان لديك فئة تُسمى book فستحصل على جدول قاعدة بيانات يُسمى books. و إن Rails تستعمل آلية قوية لذلك تُمكنها من جمع الأسماء المنتظمة و الشاذة. و عند إستعمال فئة إسمها مكون من كلمتين، فإن قواعد التسمية تميل إلى طريقة CamelCase حيث سيحتوي جدول قاعدة البيانات على الكلمتين ذاتهم مفصولتين بإستخدام “_”. على سبيل المثال، فئة تُسمي BookClub فإن جدول قاعدة البيانات الخاص بها سيسمى book_clubs، و يجب أن نلاحظ أن الإسم المفرد تبدأ كلماته بحروف استهلالية Capital. Model / Class Table / Schema Article articles LineItem line_items Deer deers Mouse Mice Person people 2.2 طريقة تنظيم قاعدة البيانات و تخطيطها إن Active Record يستعمل طريقة التسمية التي تحدثنا عنها لتسمية العواميد columns في جداول قواعد البيانات، إعتمادًا على غرض هذه العواميد. المفاتيح الأجنبية Foreign Keys هي مفاتيح أساسية في جداول أخرى و يتم إستخدامها للربط بين قواعد البيانات ببعضها البعض. طريقة تسميتها تتبع النمط الآتي singularized_table_name_id مثال على ذلك item_id, order_id المفاتيح الأساسية Primary Keys: إن Active Record يقوم بعمل عامود مكون من أرقام integers يُسمى id و مهمته هو تمييز الجدول و عناصره، فعند إستخدام خاصية التهجير Active Record Migration لعمل جداول جديدة، سيتم عمل عامود المفاتيح الأساسية تلقائيًا. هُناك أيضًا بعض العواميد الإختيارية التي تُضيف مميزات جديدة لـ Active Record: مفتاح created_at يقوم بتخزين وقت صُنع السجل مع مراعاة الوقت الحالي. مفتاح updated_at يقوم بتخزين وقت تحديث السجل مع مراعاة الوقت الحالى. مفتاح lock_version يضيف خاصية الإغلاق المتفائل لقاعدة البيانات مفتاح type يُحدد إذا ما كانت خاصية Single Table Inheritance أم لا مفتاح (association_name)_type يستخدم لتخزين النوع الخاص بـ polymorphic associations. مفتاح (table_name)_count يُستخدم لتخزين عدد الكائنات أو الأشياء objects الموجودة داخل علاقة ما، و على سبيل المثال: إذا كان لديك class تُسمى Article تحتوي على عامود يُسمى comments_count. سيقوم هذا المُفتاح بتخزين أعداد الـ comments الموجودة بكل Article. 3 صُنع نماذج Active Record إن صُنع نماذج Active Record لهو أمرٌ في غاية السهولة. كُل ما عليك فعله هو عمل صنف class فرعية من سجل التطبيق ApplicationRecord. class Product < ApplicationRecord end هذا سوف يصنع نموذج model يُسمى Product مُتصل بجدول يُسمى products بقاعدة البيانات فبواسطة ذلك سيُمكنك ربط الأعمدة الموجودة بكل صف في ذلك الجدول مع الخصائص الخاصة بنموذجك. فإعتبر أنك قُمت بإنشاء الجدول بإستخدام سطور SQL الآتية: CREATE TABLE products ( id int(11) NOT NULL auto_increment, name varchar(255), PRIMARY KEY (id) ); بإستعمال طريقة تخطيط البيانات السابق ذكرها، يمكنك كتابة كود مثل الآتي: p = Product.new p.name = "Some Book" puts p.name # "Some Book" وسنتابع في الدرس التالي التسمية،قراءة وكتابة البيانات، التوثيق، الاستدعاء والتهجير… من توثيقيات Ruby on Rails
  10. أخي أنصح بإستخدام كُتب أجنبية، وإستغلالها لتعلم اللغة لأنها مُهمة جدًا جدًا في المجال. يوجد كتاب Introduction to computer science with python
  11. راجع هذا الحساب: https://mostaql.com/u/Zaher_Shullar/projects