البحث في الموقع
المحتوى عن 'ruby on rails 103'.
-
يوضح لك هذا الدليل كيفية التأكد من صحة وضع الكائنات 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.
-
- validation
- active
-
(و 1 أكثر)
موسوم في:
-
في الدرس السابق ألقينا نظرة عامة حول التحقيقات في 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: (أو 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.
-
في الدرسين السابقين ألقينا نظرة عامة حول التحقيقات في 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.
-
في الدرسين السابقين ألقينا نظرة عامة حول التحقيقات في 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 أو تحفظ الكائن. لكن من الممكن أيضًا التحكم في وقت عمل هذه التحقيقات بإعطاء خيار 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> إضافي بالقرب من المدخل. <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.