هشام رزق الله

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

    1,435
  • تاريخ الانضمام

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

  • Days Won

    31

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

182 Excellent

6 متابعين

  1. نشعر بالأمان أكثر كلما اكتشفنا طرقًا جديدةً لزيادة أمن مواقع ووردبريس، وهذا الأمر جيّد وسيّء في نفس الوقت، فهو جيّد لأنه يعني أننا نثق بالأدوات والخدمات التي استثمرنا فيها لتأمين ووردبريس، وهي سيئة لأننا نخلط بين زيادة أمن المواقع وعقليّة "ضعها وانسها". بصراحة: يحاول القراصنة اختراق موقعك، فإذا كنت تعتقد أن موقعك صغير أو جديد ليكسب انتباه القراصنة، ففكّر من جديد، إذ يوجد 90978 هجوم أمني يحدث كل دقيقة من كل يوم، ولا يفكر القراصنة في حجم الموقع أو العمل عندما يهاجمونه. يعلم القراصنة أن لووردبريس نقاط ضعف كثيرة، لذلك إذا أردت زيادة أمن موقعك فيجب عليك التفكير كمخترق، حدد نقاط الضعف في موقعك وفكر في الطرق المختلفة التي يمكنك من خلالها استغلال هذه النقاط، وعندها فقط ستكون قادر على درء الهجمات. أين تقع أضعف البقع في موقع ووردبريس؟ ربما من الأشياء الأكثر رعبًا أن القراصنة لا يبحثون بشكل خاص على موقعك (خاصة إذا كان جديد أو صغير)، فالعديد من القراصنة يبحثون عن نقاط الضعف باستخدام bots، فالأخيرة تكشف عن المداخل للقراصنة، لذلك فإن أي موقع ووردبريس يمكن أن يكون الضحيّة. لذا من المهم التعرّف على أشهر نقاط الضعف في ووردبريس لإبقاء القراصنة بعيدين عن موقعك. كلمات المرور أي بقعة في الواجهة الخلفية (backend) أو الأماميّة (frontend) من موقعك التي تطلب اسم مستخدم وكلمة مرور هي من الأماكن الرئيسية التي يستهدفها القراصنة، ومنها منطقة تسجيل الدخول الرئيسية لووردبريس: لوحات التعليقات: حسابات التجارة الإلكترونية أو بوابات الدفع: يعرف القراصنة أن المستخدمين لا يهتمون دائمًا بإنشاء كلمات مرور قويّة لكل حساب يملكونه على الإنترنت (يتعارض هذا مع أساسيات أمن كلمة المرور 101). وسيكون هذا أحد الأهداف الأولى على موقع ووردبريس الخاص بك. التعليقات ليست التعليقات مشكلة أمنية بسبب عنصر تسجيل الدخول (إذا كان هنالك واحد)، فيمكن للتعليقات أن تكون مشكلة بسبب الرسائل غير المرغوب فيها، ولهذا فإن بعض الناس يختارون تعطيل التعليقات بالكامل في ووردبريس. وإليك مثال لتعليقات من عملاء سيئين. قد لا يؤدي هذا الرابط إلى شيء ضار، لكنه بالتأكيد لا ينتمي إلى هذه المجموعة من التعليقات. نماذج الاتصال نماذج الاتصال، أو نماذج الاشتراك، أو نماذج الدفع أو أي جزء من الموقع يطلب من المستخدمين إدخال تفاصيل هو مكان واضح يستهدفه القراصنة. بالطبع، يمكنك اختراق الموقع ومن ثم الاستيلاء على البيانات الحساسة التي أُدخلت إلى هذه الحقول، وهنالك طريقة يمكن للقراصنة من خلالها سرقة البيانات من خلال مراقبة نقرات المستخدمين إما عن طريق لوحات المفاتيح اللاسلكية أو عن طريق استخدام البرامج الضارة التي تُثبّت على أجهزة الحاسوب الخاصة بهم. قاعدة بيانات ووردبريس في حين أنه من الرائع أن ووردبريس قد بسّط تسمية الملفات وهياكل قاعدة البيانات في جميع المواقع، لكنه أحدث أيضًا مشكلة كبيرة إذ أن كل شخص منا (بما في ذلك المخترقين) يعرفون أن البادئة “wp-‎” تُستخدم لتسمية كل شيء تقريبًا، وهذا سيترك قاعدة بيانات ووردبريس مكشوفة بشكل كامل وعرضة للهجوم إذا لم يتغير ذلك. نواة ووردبريس هل تعلم أن 73% من نسخ ووردبريس القديمة تحتوي على نقاط ضعف داخلها؟ على الرغم من أنه ليس من مسؤوليتكم إدارة نواة ووردبريس (WordPress core)، فمن المؤكد أن من مسؤوليتكم أن تثبتوا أي تحديث جديد لووردبريس، فيجتهد الفريق الأمني لووردبريس دائما لجعل النواة محدّثة، ومن المهم أن يفعل مطورو ووردبريس الأمر نفسه حتى لا تبقى نقاط الضعف هذه في مواقعهم. إضافات ووردبريس إن الإضافات أكثر عرضة للانتهاكات الأمنية من نواة ووردبريس، في الحقيقة، تتحمل إضافات ووردبريس 50% من الهجمات الأمنية على مواقع ووردبريس. بالطبع، لا ينبغي لهذا أن يجعلك تخاف من استخدام إضافات ووردبريس، فهي جزء أساسي من العمل الذي تقوم به لإنشاء مواقع تفاعليّة وجذابة لجمهورنا، ومع ذلك، فهذا يعني أنك بحاجة إلى إيلاء اهتمام أكبر لما يحدث مع مجموعة الإضافات الحالية كما يجب أن تبقي عينيك وأذنّيك مفتوحة عند مراجعة إضافات جديدة لموقعك. هنالك بشكل عام طريقتان يمكن من خلالها أن تضعف الإضافات أمن موقعك: عند تحديثها من قبل المطور، لكنك لا تحدّثها في موقعك (أو عدم فعل ذلك في الوقت المناسب). عند إضافة إضافة ووردبريس مزيّفة إلى موقعك دون قصد. لذلك، تأكد من اهتمامك بهذه النقاط. قوالب ووردبريس الشيء نفسه ينطبق على قوالب ووردبريس، على الرغم من أنه لا داعي للقلق حول استخدام قالب مزيّف، فهي مجرد مسألة إصدار التحديثات من المطور في الوقت المناسب. خدمة استضافة المواقع للأسف، ليست كل شركات استضافة المواقع متشابهة وهذا يمكن أن يؤثر غالبًا على مستوى أمن الخادم، وبطبيعة الحال، يجب عليك التأكد من هذه النقاط عند اختيار خطة استضافة مواقع: التشفير وجدار حماية جانب الخادم. نوع خادم الويب NGINX أو Apache. برامج مضادات الفايروسات والبرامج الضارة. أنظمة الأمن في الموقع. توفر شهادات SSL و CDN. يوجد أيضا خطر الإصابة عن طريق عدة مواقع عند وجود عدة نطاقات تتشارك في نفس المساحة على الخادم، فإذا كانت هذه هي حالتك، فقد تحتاج إلى اتخاذ احتياطات أمنية إضافيّة على مستوى الخادم. ماذا يريد المخترقين من موقعك؟ إذا فكرت في "موقعي صغير/جديد/محلي، فماذا يريد المخترقون منه؟” فلقد حان الوقت لتغيّر رأيك، فالقراصنة لا يريدون فقط تدمير الشركات الكبيرة، انهم ببساطة يبحثون عن أي ضعف يمكن استغلاله. لذا، في المرة القادمة التي تفكر فيها بـ "ليس لديّ أي شيء يُريدونه”، فكّر في الفرص التالية التي قد يستفيدون منها: 1- حقن محتوى خبيث في بعض الحالات، يريد القراصنة ببساطة إضافة محتوى خبيث أو شيفرات برمجية على الواجهة الأماميّة من موقع ووردبريس مع أمل أن يضغط زوارك على الروابط الخاطئة، ويمكن أن يحدث هذا عن طريق التعليقات غير المرغوب فيها، أو عن طريق اختراق البريد الإلكتروني لموقعك وإرسال رسائل غير مرغوب فيها لمتابعينك، أو من خلال إرسالات (submissions) المحتوى الحالي. كمثال على الأخيرة، الق نظرة على نقطة ضعف إضافة NextGEN Gallery، فعن طريقها، استطاع المخترقين تعديل شيفرة PHP الخاصة بالموقع ومن ثم مهاجمة الموقع عن طريق هذه الإضافة. 2- نشر الفايروسات من الطرق الأخرى التي يستخدمها المخترقين لإرهاب زوارك هي عن طريق استخدام موقع ووردبريس الخاص بك لنشر الفايروسات والبرامج الضارة، ويمكنهم إجراء ذلك باستخدام شيفرة برمجية ضارة كتبوها في الواجهة الخلفية أو مع الملفات المرفوعة للتحميل في الواجهة الأماميّة وعندما يتفاعل الزوار معهم، يسرق المخترقون معلومات الزائرين أو يستخدمون حواسيبهم لنشر الفايروسات على مواقع ويب أخرى. إن إضافة BlogVault backup هي مثال جيّد على هذا، فمن خلال هذا الهجوم، استطاع المخترقون على إصابة مواقع ووردبريس التي تستعمل هذه الإضافة ببرامج خبيثة. 3- سرقة المعلومات الشخصية للزائر هذه أهم واحد يقلق حولها الزوار ويجب أن تأمل أن لا تحدث على الإطلاق لأنها مكلفة للغاية، فأي خرق أمني سيُسيء للعمل التجاري، لكن في هذه الحالة، يجب عليك تعويض زوارك وعملاءك للمال والخصوصية التي تعرضت للخطر في الهجوم، ناهيك عن فقدان الثقة في علامتك التجاريّة. يمكن للمخترقين الحصول على هذه المعلومات بطرق مختلفة ويمكنهم الاستفادة منها كثيرًا، في بعض الأحيان لمكاسب ماليّة، لكن في أحيان أخرى مثل اختراق Ashley Madison حيث أنهم يحاولون تقديم بيان. 4- سرقة بيانات أعمال خاصة تعمل الشركات بجد للحفاظ على تفاصيل تتعلق بالشركة (وخاصةً فيما يتعلق بالأمور الماليّة وتفاصيل حساب العميل) تحت الأغطيّة، ولهذا السبب، من المهم للغاية عدم وصول هذه المعلومات إلى موقع أعمال المنافس. نقطة ضعف Heartbleed هي مثال حديث لهذا النوع من الهجوم وهو بسبب مشكلة في OpenSSL وهو شيء مصنوع لزيادة حماية المواقع، وبدلا من ذلك، ما فعله OpenSSL هو إرسال بيانات عمل حساسة إلى المخترقين عند إرسالهم طلبات وهمية إلى خوادم المواقع المصابة. 5- استضافة صفحات التصيد في خادمك يشير التصيّد في المواقع بشكل أساسي إلى إنشاء القراصنة لصفحة مزيفة على موقع ووردبريس لمحاولة جمع المعلومات من الزائرين الذين يرغبون في إعطائها. ويمكنهم القيام بذلك عن طريق تضمين نموذج اتصال في الصفحة وجمع البيانات بشكل مباشرة أو يمكنهم إعادة توجيه الزائرين إلى موقع آخر حيث ستُرفع هذه المعلومات. يقوم جوجل بإدراج 50000 موقع كل أسبوع في القائمة السوداء بسبب عمليات التصيّد. 6- استضافة صفحات شرعية في خادمك بعض القراصنة يبنون صفحات شرعيّة في مواقع ووردبريس من أجل تحسين SEO (تحسين محركات البحث) الخاص بهم، وتتحدث هذه الصفحات عن شركتهم الخاصة وروابط لهم من أجل تحسين من قوّة موقعهم في محركات البحث، أو قد يختارون تخطي الصفحة المقصودة ويستخدمون نهج أكثر دقة لتعزيز SEO الخاص بهم، في هذه الحالة، سيستخدمون نظام الروابط الخلفية (backlinks) من موقعك لمواقعهم. 7- حمل زائد على خادمك عندما قيام القراصنة بتحميل زائد على خادمك عن طريق أعداد كبيرة من الزيارات، وهذا ما يعرف بهجوم الحرمان من الخدمات (DdoS)، فسيتوقف موقعك عن العمل عندما يصلون إلى ذلك، وسيفوزون، ولماذا يفعلون ذلك؟ ما الذي يمكنهم الحصول عليه من إيقاف موقعك؟ حسنًا، ربما يحصلون على لذة الانتصار، أو بسبب ثأر شخصي ضد العلامة التجارية، أو ربما موقعك هو واحد من عدة ضحايا في هجوم واسع النطاق، أو ربما فعلوا ذلك من أجل المطالبة بفديّة. 8- سرقة عرض نطاق (Bandwidth) الموقع تحدثتُ سابقا كيف يمكن سرقة الصور من موقع ووردبريس الخاص بك بعلمك أو بدون علمك، وواحدة من هذه الطرق هي عن طريق الربط الساخن (hotlinking)، والذي يحول موقعك إلى استضافة لحركة مرور بيانات (traffic) المواقع الأخرى عن طريق روابط الصور. ومع ذلك، هنالك طرق أخرى يمكن من خلالها للقراصنة سرقة موارد خادمك لاستضافة أنشطتهم السيئة مثل تعدين البيتكوين وهجمات الحرمات من الخدمة وهذا بالضبط ما حدث في قضيّة اختراق Monero mining حيث أصبحت المواقع التي اخترقت "عبيدًا”، تُستخدم في أنشطة التعدين للقراصنة. 9- تخريب موقعك وبطبيعة الحال، هنالك تخريب المواقع، ففي أغلب الأحيان، يفعل المخترقون هذا لإنشاء هويّة لأنفسهم بينما يضرون في الوقت نفسه علامتك التجاريّة، ولقد حدثت هذه التشويهات في مجموعة كبيرة من مواقع ووردبريس، واستمرت في حدوث حتى بعد تحديث ووردبريس لأن المستخدمين فشلوا في التحديث في الوقت المناسب. الخاتمة لإنهاء هذا بملاحظات إيجابيّة، لنحاول التركيز على ما نعرفه: لا، فوردبريس ليس "غير قابل للقهر”. ولكن نعم، لدينا الوسائل لوضع دفاع جيّد ضد المتسللين إذا كنا نعرف إلى أين ننظر. كتذكير، هذا ما يمكنك القيام به: عمل نسخة احتياطية من موقعك بانتظام. تأمين موقعك على كافة المستويات: الخادم، والنواة، والإضافات، والقوالب، وحتى جهاز حاسوبك والشبكة. استخدام إضافة أمنيّة. استخدام CDN. استخدام شهادة SSL. تأمين كلمات السر الخاصة بك. لا تنسَ فحص نقاط الضعف في موقعك بانتظام للتأكد من أن موقعك خالٍ منها. ترجمة -وبتصرّف- للمقال Do You Know Why Hackers Are Targeting Your WordPress Site?‎ لصاحبه Brenda Barron
  2. في هذه السلسلة من المقالات، سنتحدث عن منصة jQuery Mobile التي تساعدك على إنشاء مواقع ويب متجاوبة للهواتف. بدايتك مع jQuery Mobile ما هو jQuery Mobile المحمول يوفرjQuery Mobile مجموعة وفيرة من أدوات التطوير التي تجعل موقع ويب الموجه للهواتف متجاوبًا ومرنًا وبسيطًا. يُعرّف jQuery ببساطة على أنه مجموعة من إضافات وودجات (widgets) jQuery تهدف إلى توفير API متعدد المنصات لإنشاء تطبيقات ويب للهواتف. من حيث الشيفرات البرمجية، jQuery Mobile يشبه jQuery UI، لكن في حين أن jQuery UI موجه لتطبيقات سطح المكتب، فإن jQuery Mobile موجه للهواتف المحمولة. ما يجب معرفته حول إنشاء مواقع ويب للهواتف يجب عليك معرفة ثلاثة كلمات رئيسية عند تطوير مواقع ويب للهواتف، وهي أنه يجب أن يكون الموقع الموجه للهواتف: متجاوبًا: يتضمن كيف يبدو شكل الصفحة عند التنقل، وكيف يُضْغط على الزر وكيف تُحمّل البيانات على الهاتف. مرنًا: يعني أنه يمكن تخصيص الموقع عن طريق المستخدم ليناسب رغباته. بسيطًا: يعني أن الموقع يسهل تصفحه عن طريق الهاتف. ما يجب معرفته حول jQuery Mobile للمطورين أثّرت jQuery بشكل كبير على العالم الناشئ من تطوير وتصميم الويب، فلقد غيّرت من طريق تنفيذ واستخدام جافا سكربت على مواقع وتطبيقات الويب ولذلك اختارتها مايكروسوفت كإطار جافا سكربت المفضل، وضمّنت دعم الإكمال التلقائي (auto-completion) لـ jQuery داخل visual studio، وبالتالي فإن jQuery mobile هي امتداد مدعوم وموثوق لمكتبة jQuery. لماذا jQuery Mobile؟ (تحتاج إلى معرفة jQuery Mobile كمطور) كما أشرت في "ما يجب معرفته حول jQuery Mobile للمطورين”، أدى ظهور جيل أجهزة الهواتف إلى الحاجة إلى تطبيقات ويب متجاوبة ومرنة وبسيطة وبالتالي ارتفعت بسرعة الحاجة والطلب على jQuery mobile (إطار عمل jQuery)، وحان الآن الوقت بالنسبة لك كمعلم أو مبتدئ في API مواقع الهواتف الجوالة للقفز والمشاركة مع هذا المشروع. الجهاز الذي يُشغل jQuery Mobile يعتمد عمل jQuery في مختلف الأجهزة على المتصفح ونظام التشغيل. فالمتصفحات التي تدعم jQuery Mobile هي المتصفحات الحديثة التي تدعم وسوم HTML5 والقليل من CSS3. فالأجهزة التي تدعم jQuery mobile هي الحواسيب المكتبية والمحمولة، أنظمة الكل في واحد (all-in-one)، الأجهزة اللوحيّة، الهواتف الذكية، أندرويد، iOS، بلاك بيري (النسخ الحديثة)، webOS، ويندوز للهواتف، وأجهزة القراءة الإلكترونية، فيدعم jQuery mobile أجهزة كيندل kindle التي تتضمن متصفح مبني على Webkit تجريبي. ما يحتاجه المطور المحترف لإنشاء مواقع ويب للهواتف باستخدام jQuery Mobile لتطوير التطبيقات، ستستخدم: بالنسبة لنظام ويندوز التطبيقات: Komodo IDE، eclipse، iWeb، Microsoft FrontPage، Aptana studio، Dreamweaver، notepad++. وسنستخدم Dreamweaver في هذا الدرس. بالنسبة لنظام OsX التطبيقات: Coda، espresso، textwrangler، kod. لغات البرمجية التي يجب على مطور الويب معرفتها هي HTML5 و CSS3 وجافا سكربت. يتكون jQuery Mobile من أربعة ملفات: ملف جافا سكربت، ملف CSS، وملفي PNG. يُحمَّل ملف جافا سكربت بشكل مقصود بعد تحميل مكتبة jQuery الأساسية، ويقوم هذا الملف بمهام كثيرة مثل إنشاء الويدجات وتطبيق مستمعي الحدث (event listeners) وتفعيل API. ورقة أنماط CSS تحدد مخطط ومظهر عناصر صفحة jQuery Mobile، بالإضافة إلى تحديد الانتقالات (transitions) والرسوم المتحركة مع تحويلات CSS3. يمكنك تحميل كامل حزمة jQuery Mobile (مكتبة جافا سكربت، CSSـ والرسومات) أو يمكنك الوصول إليها عن طريق مشروع CDN، راجع صفحة تحميل مشروع jQuery Mobile للتفاصيل، سنستخدم CDN في أمثلتنا لهذا الدرس. DOCTYPE لبناء محتوى HTML لموقع الهاتف DOCTYPE انتقالي لـ HTML4 بالنسبة للمطورين الراضين باستخدام وسوم HTML المهملة لكن يريدون الانتقال إلى HTML 4 يمكنهم استخدام DOCTYPE الانتقالي والذي يسمح للمتصفح تحليل الوسوم المهملة وعرضها دون رمي (throw) أية أخطاء. <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> DOCTYPE الصارم لـ HTML4 يمكن للمطورين الذي لا يرغبون بتضمين دعم للوسوم المهملة وإمكانية وجود أخطاء تنسيق عند استخدام وضع التوافق 'compatibility' استخدام DOCTYPE الصارم والذي يخبر المتصفح برمي أخطاء عند تضمين وسوم مهملة في ملف HTML عند محاولة تحميله، وسيكون هذا مفيدًا لضمان عملك على معيار HTML4. DOCTYPE من أجل HTML5 يعمل DOCTYPE للإصدار HTML5 تقريبًا على جميع المتصفحات القديمة وهو يُستخدم بالفعل على مواقع عديدة اليوم. لاستخدام HTML5 DOCTYPE في ملف HTML، استخدم المقتطف التالي: <!DOCTYPE html> هيكل الموقع الأساسي باستخدام HTML5 DOCTYPE <!DOCTYPE html> <html> <head><title></title></head> <body></body> </html> العمل مع هيكل HTML5 و CSS و جافا سكربت بناء وتقديم المحتوي في HTML5 <!DOCTYPE html> <html> <head> <title>Titles should be short descriptions of the page</title> <meta charset="utf-8"> </head> <body> <div> <h1>h1 tags should contain the most important information on your site</h1> <p>Paragraph tags should be where most of your text content lives, or used as a separation between sections.</p> <ul> <li>This is a list element</li> <li>This is another element, notice the bullets and indentation </li> </ul> <p>You probably noticed that I used a "div" tag to wrap these other tags in. I'm using it as a container.</p> </div> </body> </html> نعرف بالفعل ما تفعله هذه الشيفرة البرمجية، لكن دعنا نلقي نظرة حول شكله في الواقع. ستظهر لك الصورة في الأسفل شكل HTML الذي كتبناه: CSS في بناء وتقديم محتوى HTML5 اضغط على زر الإدخال بعد الوسم <title> </title> وأضف المقتطف كما هو موضح في رابط الصورة التالية لربط ملف الأنماط css. إلى ملف html. الرئيسي. يجب وضع الشيفرة البرمجية التالية في الملف hist.css @charset "utf-8"; /* CSS Document */ body { background:#0CF; font-family: Helvetica, Arial, sans-serif; font-size: 0.75em; } h1 { font-size: 200% } p { margin: 5px 0; padding: 0 3px; } #year{ text-align:center; font-weight:bold; font-size:200%; } .small { font-size: 80%; } تُظهر لك الصورة في الأسفل مظهر HTML الجديد بعد ربط ملف CSS . جافا سكربت في بناء وتقديم محتوى HTML5 ملخص لوضع وسوم جافا سكربت في ملفك: تحميل السكربتات في عنصر head: يجعلها تُحمّل أولا لكن قد تُؤثّر سلبا على وقت التحميل. تحميل السكربتات في body : تبدو فكرة جديدة لكنها تخلق مشاكل مع الصيانة وترمي (trows) تأخيرات التحميل المحتملة. تحميل السكربتات قبل إغلاق وسم body : سيبدو تحميل موقع أسرع لكن قد يؤدي ذلك إلى نتيجة غير مقصودة لنقص وظائف الموقع في الثواني الأولى للتحميل. دعنا نضع السكربتات في وسم head والتي هي الحالة المفضلة لكل مطور. <script src="js/javascript.js" type="text/javascript"></script> </head> يجب وضع السكربت التالي في ملف javascript.js // JavaScript Document window.onload = setYear; function setYear() { var currentYear = new Date(); document.getElementById('year').innerHTML = currentYear.getFullYear(); } ستوضح لك الصورة أدناه شكل HTML الجديد بعد ربط ملف js .. تعلمنا قليلا جول استخدام الحالي لهيكل HTML وربط CSS وتحميل السكربت (جافا سكربت)، والآن لنتعلم كيف نستخدم المهارات التي تعلمناها في jQuery mobile. ترجمة -وبتصرّف- للمقال jQuery Mobile Lesson 1 لصاحبه Andrew اقرأ أيضًا الدرس الثاني: التضمين، تهيئة الصفحة، التنقل بين الصفحات وأحداث التحميل
  3. لقد استغرقت بعض الوقت لتعلم كيفية استخدام جافاسكربت في ووردبريس معنا، ولقد جمعنا أيضًا مجموعة من مكتبات جافاسكربت والمصادر على طول الطريق لمساعدتك في البرمجة، ولكن ما الذي ستفعله بالمهارات التي اكتسبتها؟ توجد العديد من الأسباب التي تجعلك تضيف جافاسكربت مخصص إلى موقع ووردبريس وتوجد أيضًا العديد من الطرق التي يمكنك من خلالها تنفيذ ذلك، لكن يجب أن تكون حذرًا حول كيفية القيام بذلك، فالتنفيذ الخاطئ لجافاسكربت يمكن أن يلحق ضررًا أكثر مما ينفع. في الدليل اليوم السريع لجافاسكربت، سنتحدث حول لماذا قد ترغب في إضافة شيفرات جافاسكربت مخصصة إلى موقعك وكيف تقوم بذلك بالطريقة الآمنة والسليمة (بما في ذلك استخدام إضافات ووردبريس). لماذا قد ترغب في إضافة جافاسكربت مخصص إلى ووردبريس عند كتابة الشيفرة البرمجية لموقع ووردبريس، توجد ثلاثة عناصر ستحتاجها: HTML CSS جافاسكربت إن HTML وCSS رائعين، فهما يضعان أساس موقع ووربريس الخاص بك، ومع ذلك، لا يمكنك استخدامهما لتغيير بعض سلوك موقعك، فعلى سبيل المثال، قد تحتاج إلى استخدام جافاسكربت للقيام بالتالي: تغيير، إخفاء، عرض عناصر HTML. إضافة قيم لمتغيرات CSS وتشغيل عمليات معقدة عليها مثل متغيرات الدمج أو توفير رد بعد اتخاذ إجراء (مثل نقرة). تغيير تخطيط وتصميم قوالب ووردبريس الخاص بك (إذا كنت محظور من التحكم على بعض العناصر). تغيير أو تعزيز وظيفة إضافة ووردبريس. عزز موقعك مع محتوى حيوي مثل مربعات التمرير (sliders)، والرسوم المتحركة (animation)، ومشغلات الفيديو، والقوائم المنسدلة، وتأثيرات التمرير، والآلة الحاسبة، والعناصر التفاعليّة الأخرى. ربط مصدر خارجي أو عنصر إلى موقعك، مثل Google Analytics أو API من مصادر خارجية. وهنا يمكن لجافاسكربت مساعدتك. ومع ذلك، إن تطبيق شيفرات جافاسكربت ليس سهلًا مثل HTML و CSS، ليس عليك فقط أن تكون حذرًا حول كيفية كتابة التعليمات البرمجية ولكن عليك أيضًا أن تكون حذرًا حول كيف وأين يمكنك إضافتها إلى ووردبريس. كيفية إضافة جافاسكربت مخصصة إلى ووردبريس إذا أتقنت HTML وCSS و تريد إضافة بعض الحيوية إلى موقعك سيكون الوقت مناسبًا لإضافة شيفرات جافاسكربت مخصصة إليه، لكن كيف يمكنك القيام بذلك وأين يمكنك وضعه؟ والأهم من ذلك، هل هذا الأمر مهم؟ كقاعدة أساسيّة، ينتمي جافاسكربت إلى أحد هذه الأماكن: في رأس القالب لسكربتات تطبيقات جانب الموقع. داخل جسم صفحة ويب للتطبيقات الصفحة الخاصة. لا يجب عليك إضافة كامل الشيفرة البرمجية في تلك الأماكن، إذا أردت تسريع تحميل صفحات الويب وتسهيل قراءة الشيفرة البرمجية، يمكنك إنشاء ملفات جافاسكربت مستقلة (‎.js) واستدعائها باستخدام مرجع مثل هذا: filename.js تبدو بسيطة، أليس كذلك؟ حسنًا، تذكر أن جافاسكربت هي لغة برمجة، وليس شيء يمكنك حقنه بسهولة في صفحات الويب مثل HTML وCSS، لذا، هذه بعض القواعد التي يجب عليك اتباعها عند إضافة جافاسكربت مخصصة إلى موقع ووردبريس: القاعدة رقم1: لا تستخدم محرر ووردبريس ما لم تضف سكربت صغير للغاية إلى صفحة منفردة أو تستدعي ملف منه، فمحرر ووردبريس للصفحات ليس مكانًا مناسبًا لكتابة شيفرات جافاسكربت، وسيبطئ من تحميل صفحتك وستخلق فوضى في الشيفرات البرمجية. القاعدة رقم2: لا تعدّل ملفاتك مباشرةً تتعلّق هذه القاعدة بملفات القوالب والإضافات، فعلى الرغم من أن جافاسكربت سيساعدك على إضافة أو تغيير وظيفة في ووردبريس، إلا أنه من السيئ إضافة شيفرة جافاسكربت مخصصة إلى ملفات الرأس هذه (header files). من أهم الأخطاء التي يرتكبها المبتدئين هي إفساد الشيفرات البرمجية المكتوبة جيّدًا من قبل المطور، وواحدة من الطرق التي تحافظ على عمل موقعك بشكل طبيعي هي تطبيق الممارسات الصحيحة أثناء البرمجة، لأن شيفرة جافاسكربت خاطئة قد تفسد ذلك. ثانيًا، ستخسر توجيهات جافاسكربت المخصصة عند تحديث القالب أو الإضافة، فعلى الرغم من أن جافاسكربت ينتمي إلى رأس القالب ويمكنك تعديل ملف header.php، لكن لا تفعل هذا. وأخيرًا، إذا كنت تفكر في التحايل على هذه المشكلة من خلال إنشاء "قالب فرعي" وتطبيق جافاسكربت المخصصة هناك، فلا تقم بذلك، فعند تحديث ملفات header.php أو footer.php باستخدام جافاسكربت، فقد تنشئ عن غير قصد تعارضًا مع إضافات أخرى تعمل في موقعك، وهذا سيبطئ من سرعة موقعك أو سيتوقف موقعك بالكامل لأنه لا يعرف كيفية التعامل مع هذه الطلبات المتزامنة. ملاحظة: تتعلق هذه القاعدة بالمطورين الذين يستخدمون إضافات أو قوالب من مصدر ثالث، فإذا كنت تكتب قوالبك أو إضافاتك بنفسك، فيمكنك إضافة جافاسكربت مباشرةً إلى ملف header، ومع ذلك، ستحتاج إلى استخدام نظام صفْ كما يشرحه المقال التالي. القاعدة رقم3: إنشاء ملفات منفصلة لجافاسكربت نصحناك بعدم إضافات شيفرات جافاسكربت مباشرة إلى الملفات أو الصفحات في ووردبريس، فما هي الطريقة الصحيحة لإضافتها؟ هنالك طريقتين لفعل ذلك، الأولى عن طريق إنشاء ملفات جافاسكربت منفصلة والثانية والتي سأشرحها في القاعدة رقم 4، هي عن طريق استخدام إضافات ووردبريس. كما ذكرنا سابقًا، ستسبب إضافة شيفرات جافاسكربت مخصصة مباشرةً إلى ووردبريس فوضى في الشيفرات البرمجية وقد تؤدي إلى مشاكل خطيرة مثل شاشة الموت البيضاء، لكن إذا أردت فقط تطبيق سكربت إلى صفحة واحدة، فستحتاج إلى طريقة لحقن الشيفرة البرمجية في المكان المخصص بدلا من إضافتها والضغط على بقية الصفحات الأخرى بطلبات HTTPS غير ضروريّة. لذا يجب عليك إنشاء ملف جافاسكربت منفصل. يتضمن ووردبريس Codex على بعض الخطوات حوّل ما يجب عليك فعله مع ملفك، ولتسهيل الأمر، ينصح بالتالي: مهما كان عدد السكربتات، تأكد من تعريف الدالة لكل سكربت داخل الملف، فعلى سبيل المثال: بعد ذلك، استدعي الملف من رأس موقعك عن طريق استخدام سكربت مثل هذا (يمكنك إضافة هذا إلى الرأس باستخدام إضافة): وأخيرًا، ستحتاج إلى استدعاء دالة جافاسكربت الحاليّة التي عرّفتها في الملف حتى لو كان هنالك سكربت واحد فقط فستحتاج إلى تعريفه في شيفرتك البرمجية. إذا كانت شيفرة جافاسكربت تنطبق على كامل الصفحة أو الموقع، يمكنك إضافة استدعاء جافاسكربت التالي إلى الرأس (header)، وإذا احتجت إلى تنفيذ جافاسكربت في مكان ما في الصفحة، فيجب أن يكون داخل جسم موقعك: القاعدة رقم 4: استخدام إضافة ووردبريس عندما يتعلق الأمر بجافاسكربت، ستساعدك الإضافات التالية على الالتفاف على المشكلات التي تنشأ عند وضع جافاسكربت مباشرةً في ملفات ووردبريس، فبدلًا من ذلك، ستسمح هذه الإضافات للخادم باستدعاء السكربت فقط عند حدوث "الحدث”، ويسمح لك هذا بالالتفاف على ثيمات وإضافات ووردبريس عند التحديث والذي يمسح لك أيّة تغييرات طبّقتها مباشرةً عليهم. إضافة Insert Headers and Footers أُنشأت هذه الإضافة بواسطة WP Beginner لمساعدة المطورين على إضافة شيفرات برمجية مخصّصة بسهولة إلى رأس وذيل القوالب، فهو يعطيك أداة مريحة - خارج ملف header.php – التي تسمح لك بإضافة جميع السكربتات المخصّصة، فقط كن على علم بأن هذا البرنامج هو المساعد مثالي لك فقط إذا كنت تحاول إجراء تغييرات على جانب الموقع باستخدام جافاسكربت. على الرغم من وجود إضافتين لإضافة الشيفرات إلى الرأس والذيل في مستودع ووردبريس، إلا أن هذه من WP Beginner هي الأكثر شعبيّة. إضافة Shortcoder بالنسبة إلى الأشخاص الذين يرغبون بإضافة شيفرات جافاسكربت مخصصة إلى صفحات أو مشاركات فرديّة، فقد ذكرْتُ عدة طرق يمكنك من خلالها إجراء ذلك أعلاه، فيمكنك إما إضافته إلى HTML مباشرةً إذا كان السكربت صغيرًا أو يمكنك استدعاء ملف جافاسكربت الذي يمكنه حمل كامل شيفرتك البرمجية، كِلا هاتيّن الطريقتين تضيفان عددًا من الأسطر البرمجية إلى موقعك ويمكن أن يجعل الأمور أكثر تعقيدًا وأكثر صعوبة عند القراءة، لذا يمكنك حل ذلك عن طريق استخدام إضافة Shortcoder. من الفوائد الأخرى لاستخدام Shortcoder هي اختصار الوقت، لنفترض أن لديك دالة جافاسكربت خاصة تريد تطبيقها على صفحاتٍ كثيرةٍ، فلن تحتاج إلى نسخ السكربت إلى كل واحدة منهم، فيمكنك إنشاء شيفرة برمجية مختصرة لتمثيل تلك الدالة وإضافتها في أي مكان تحتاج إليه. خاتمة إن فهم كيفية استخدام جافاسكربت لتعزيز قوة قوالب، وإضافات، ومحتوى ووردبريس هي طريقة قويّة لتعزيز قدرتك على تطوير ووردبريس، ومع ذلك، يجب أن تكون حذِرا في كيفية استخدامها حتى لا تعطّل أداء موقعك أو تتسبب في مشكلات تكامل التي تحاول تشغيلها في موقعك، التزم بالقواعد أعلاه وستكون على ما يرام. ترجمة -وبتصرّف- للمقال Learn How to Add Custom JavaScript to WordPress the Right Way لصاحبه Brenda Barron
  4. يجب أن يهتم كل شخص يمتلك، أو يبني، أو يدير أو يستضيف مواقع ووردبريس بالأمن، ليس لأن ووردبريس منصة غير آمنة بل لأنه نظام إدارة المحتوى الأشهر في العالم وهو هدف سهل للمخترقين ولذلك لا يجب على مدونات ووردبريس التوقف عن الحديث حول أمن ووردبريس. من فوائد الاهتمام الكبير بالأمن وجود مجموعة كبيرة من الحلول لمعالجة ذلك، فعلى سبيل المثال، توجد أدوات مراقبة أمنية مثل WP Checkup ستهتم بالجزء الأول من المعركة ضد نقاط ضعف ووردبريس، ولكن هذا ليس كافيًا، ستحتاج أيضًا إلى أدوات تمكنك من إصلاح الثغرات الأمنية والانتهاكات. هذا هو سبب وجود إضافات ووردبريس أمنيّة، وبالتأكيد، يجب عليك استخدام أدوات أخرى وجدران حماية خارج ووردبريس، لكن هذه الإضافات تساعدك على وضع جدار دفاعي قوي داخل موقعك، وإذا لم تكن معتادًا على إضافة Defender، فأنصحك بإلقاء نظرة عليها. يوجد الكثير من الأشياء داخل هذه الإضافة – في كلا الإصدارين المجاني والمدفوع- لذلك لنكتشفهم ونرى كيف يمكنك الاستفادة القصوى من هذه الإضافة. دافع عن موقع ووردبريس الخاص بك باستخدام النسخة المجانية من إضافة Defender بالنسبة إلى الأشخاص الخائفين من الانتقال مباشرة إلى إضافة ووردبريس مدفوعة (خاصة لواحدة تتعامل مع أمن ووردبرس) دون تجربتها، هنالك أخبار جديدة، يمكنك تحميل Defender مجانا من مستودعات ووردبرس. لنلق نظرة فاحصة على المميزات التي تحتاجها للاستفادة من النسخة المجانية من Defender والحصول على أقصى استفادة لزيادة الأمن الخاص بك: تحصين تسجيل دخول ووردبريس على الرغم من أن لوحة تحكم Defender تركز على أشياء مثل ترتيب قاعدة البيانات وإضافة تدابير أمنية جديد إلى أشياء مثل PHP ومحرر الملفات، إلا أنني أقترح عليك بالبدء في قسم IP Lockouts من الإضافة. صحيح أن Defender يعطي أولوية لفحص (Scanning) وتنظيف (cleanup) ووردبريس من داخل لوحة التحكم، لكن، على الرغم من ذلك، تأكد من إغلاق بابك الأمامي أولًا (على سبيل المثال صفحة تسجيل الدخول). عندما تحصّن تسجيل الدخول ضد هجمات القوة العمياء (brute force) عن طريق التأكد من عناوين IP والقوائم السوداء، فستتمكن من استخدام هذه الإضافة لتنشيط المراقبة (monitor) وإصلاح موقعك. ابدأ بـ Advanced Tools، فسيتيح لك هذا القسم تشغيل المصادقة الثنائية (two-factor authentication) لمستخدمي ووردبريس. بالإضافة إلى ذلك، توجد إعدادات إضافية يجب تكوينها، مع هذه الخيارات، يمكنك تسهيل الحصول على أداة مصادقة جوجل (Google Authenticator) للمستخدمين، ويمكنك أيضًا استخدامها لمراقبة المستخدمين والتأكد من التزامهم بأفضل الممارسات لتأمين كلمة المرور. الآن، لننتقل إلى قسم IP Lockouts، ويمكنك استخدام هذه الأساليب لتحصين عملية تسجيل الدخول: قواعد تسجيل الدخول، والقيود، وعمليات الإغلاق (Lockouts). حظر برامج التتبع عن طريق خطأ 404. حظر IP ووضعه في القائمة السوداء (أو وضعه في القائمة البيضاء). لا تنسَ أيضًا استخدام إعدادات Logs و Notifications لإعلامك بانتظام عند حدوث محاولات دخول خبيثة إلى نظام تسجيل الدخول. اتبع إجراءات الأمان الموصى بها من الأفضل لو ألقى شخصا ما نظرة على موقعك وأخبرك ماذا تفعل؟ هذا ما يفعله Defender عن طريق Security Tweaks، وليس هذا فقط بل يقدم لك تفسيرات كاملة لكيفية تأمين موقعك بنجاح: سيخبرك Defender أيضًا أين توجد المسائل الخطرة وكيفية إصلاحها: وهذا سيسهّل عليك تحديد نقاط ضعف موقعك وكيفية إصلاحها، ما عليك سوى الضغط على زر “Fix the Issue” عندما تكون مستعدًا أو “Ignore” لتخطيه والانتقال إلى الخطوة التالية. افحص ملفاتك هل قلقت على ما سيفعله المخترقون بملفاتك خلف الكواليس؟ على سبيل المثال، صفحة الموت البيضاء أو بعض الثغرات الواضحة في واجهة موقع ووردبريس قد تُكسِب شخصًا ما وصولًا غير مبرر، لكن كيف يفترض بك أن تعرف حدوث ذلك في قاعدة بياناتك؟ فهي ليست كتمشيط ملفاتك أو البرمجة بالأسلوب المعتاد، فكيف يمكنك اكتشاف شيء مثل هذا؟ ستهتم إضافة Defender بهذا لك على المستوى الأساسي. عندما تستخدم أداة File Scanning، سيفحص Defender الملفات الأساسية وللكشف عن أي تغيير لم يتوقع العثور عليه، فإذا اكتشف أي من هذا، فسينذرك Defender بذلك، وللحصول على هذه التنبيهات، تأكد من تحديث الإعدادات في File Scanning لكي تظهر للشخص المناسب وحتى تعرف ما الذي تبحث عنه بالضبط (إذا اخترت تخصيص الرسالة). وبمجرد رؤيتك لنتائج الفحص، لديك خياران، إما إصلاحها واستعادة الملف مرة أخرى بضغطة زر واحدة، أو إذا كنت تعرف الملف وترغب في الاحتفاظ به كما هو، فتجاهل هذا التحذير ببساطة. دافع عن موقع ووردبريس الخاص بك عن طريق إضافة Defender المدفوعة إذا كنت تملك عضوية في WPMU DEV أو كنت تنوي ترقية الإضافة Defender إلى الإصدار المدفوع، فهذا القسم لك. تتشابه النسخة المدفوعة مع النسخة المجانية عند تشغيلها لأول مرة في ووردبريس، لذلك لا تنزعج، فعلى الرغم من امتلاكها لنفس لوحة التحكم، إلا أنها تمتلك مجموعة كبيرة من مميزات الأمنية الإضافية لموقعك. وهذه التي تحتاج إلى الاستفادة منها الآن: التحقق من حالة القائمة السوداء لا أحد يريد أن يكون في القائمة السوداء، وخاصة عندما يتعلق الأمر بموقع ووردبريس. وإذا لم تعرف هذا، فهذا يعني أن محركات البحث حظرت موقعك لأنه يشكل تهديدًا أمنيًا للمستخدمين، ومع ذلك، فليس كما لو كانت جوجل سترسل إليك رسالة إلكترونية تقول فيها "أهلا، قررنا حظر موقعك من البحث”، لكن بدلًا من ذلك، ستحتاج إلى أداة مثل هذه لتخبرك عندما يحدث ذلك. بمجرد أن يكتشف Defender أن موقعك أُدرج في القائمة السوداء، يمكنك بدء البحث في جميع عمليات الفحص والسجلات لتحاول معرفة مصدر الخرق وإغلاقه في أسرع وقتٍ ممكن. عمليات فحص تلقائية في النسخة المجانية من هذه الإضافة، ستجد خدمة فحص ومراقبة أمنيّة مدمجة في Defender، ومع ذلك، ماذا لو كان بإمكانك جعلها أسهل لفحص موقعك وإعلامك بالنتائج؟ وماذا لو رغبت في فحص المشاكل في أجزاء غير الجوهر؟ حسنًا، هذا هو سبب ترقيتك إلى النسخة المدفوعة. باستخدام الإضافة المدفوعة، يمكنك فحص: جوهر ووردبريس. إضافات قوالب ووردبريس. شيفرات برمجية مشبوهة موجودة في موقعك. ويمكنك أتمتة الفحص أيضًا حتى تتمكن من الاطمئنان أن شخص آخر يراقب أمن موقعك حسب حاجتك. تلقي سجلات التدقيق بالإضافة إلى مراقبة الجوهر والبرامج المثبتة في ووردبريس، يمكنك أيضًا تشغيل سجلات التدقيق (audit logs) داخل Defender. سيراقب Defender بشكل افتراضي جميع الخطوات التي تقوم بها على موقعك، اعتبره نظام مراقبة خاص يخبرك من قام بالفعل، لأي ملف وفي أي وقت. وهذا الأمر مفيد عند تعقب تصرفات المخترقين في موقعك، بالإضافة إلى أنه مفيد عندما "يكسر” موظف أو عميل شيئًا وتحتاج إلى معرفة ما الذي حدث. تسمح لك Event Logs بإجراء عمليات بحث أكثر تفصيلًا في السجلات لتحديد الأماكن التي انحرفت فيها الأمور، مما يوفر لك الوقت لتحري الخلل وإصلاحه عندما تشعر بالعجز عن رؤية سبب المشكلة. إنشاء تقارير أمنية مخصصة وتلقائيّة هذه طريقة أخرى تجعل فيها النسخة المدفوعة أمن موقعك أسهل بالنسبة لك. بالتحديد، توجد ثلاثة تقارير أمنية يمكنك إنشاؤها، تخصيصها وجدولتها في Defender: فحص الملفات. سجلات التدقيق. إغلاق IP. ذكرنا كل واحد منها في هذا المقال، لكن ما لم نذكره كان كم من السهل تخصيصه وأتمتة إرسال هذه التقارير الأمنية إليك (ولبقية المسؤولين) عن استخدام النسخة المدفوعة. عملية الإعداد سهلة للغاية: ببساطة، اختر التكرار والوقت التي ترغب فيه في الحصول على التقرير ومن ثم ستعرف ما الذي يحدث من الإغلاق إلى نشاط مدقق دون الحاجة إلى تسجيل الدخول مرة أخرى إلى ووردبريس. خاتمة ليس الهدف من إضافات ووردبريس تركيبها وتركها، فإذا أردت حقًا الاستفادة من جميع مميزات Defender (ناهيك على إضافات ووردبريس الأخرى) ستحتاج إلى معرفة كيف تعمل، وبهذه الطريقة، يمكنك ضبطها لتحسين سير العمل وزيادة النتائج. ترجمة -وبتصرّف- للمقال Get the Most Out of Defender and Maximize WordPress Security لصاحبته Brenda Barron.
  5. يحتار المطورون في اختيار أفضل إطار لمشاريعهم وسيكون هذا تحديًا حقيقيًا للمبتدئين في الأطر الحديثة. بعد العمل على الأطر الثلاثة (Django، Laravel و Rails – والذي يُعرف باسم Ruby On -rails)، سأقارن بين هذه الأطر الرائعة على أساس شعارها، سهولة تعلمها، أدائها، قوة وضعف مكتباتها وقوالبها، دعمها، آفاقها المستقبلية، فرص العمل، التكلفة والصيانة. ملاحظة: ينتقد بعض المعجبين عند التحدث عن نقاط ضعف أطرهم، ولا أستطيع فعل أي شيء لأنه لا يمكن إخفاء الحقيقة، كل إطار لديه بعض المزايا مع بعض العيوب. المقدمة لغة البرمجة أهم فرق بين هذه الأطر هي أن Django بلغة بايثون، Laravel بلغة PHP وRails بلغة الروبي، لذا إذا كنت تنوي استخدام أي من هذه الأطر فيجب عليك تعلم لغتها أولاً، وبسبب هذا، العديد من المطورين يختارون الإطار الذي يتطابق مع اللغة التي يعرفونها. إن التحول من لغة إلى أخرى ليس صعبًا بل يحتاج إلى بعض الوقت، وإذا احترت في اختيار لغة البرمجة، فهذه مقارنة بين لغات بايثون و PHP وروبي. الشعار جميع هذه الأطر من نوع MVC وشعارها ‘لا تكرر نفسك’ أي تدعم إعادة الاستخدام وقابلية النقل، وجميعها مشاريع مجانية ومفتوحة المصدر. المواقع بعض المواقع المعروفة تستخدم Django مثل Pinterest، Instagram، Mozilla، The Washington Times، Disqus، the Public Broadcasting Service و Bitbucket. في حين أن Laravel هو إطار جديد، حيث صدر في يونيو عام 2011، لكنه أصبح مشهورا جدا، ومن بين المواقع التي تستخدمه هي Deltanet Travel، Sublimity، Neighborhood Lender، Sendity و MyRank. يعتبر Rails من الأطر الرائعة فمن المواقع التي تستخدمه Twitter، Shopify، SoundCloud، Heroku، Github، Bloomberg و Hulu. سهولة التعلم على الرغم من أن الأطر الثلاثة لديها مجتمعات كبيرة وتوثيق رسمي، إلا أن تعلم Django وLaravel أسهل بكثير من تعلم Rails، فالتوثيق الحالي ل Django يجعلها الأسهل، وإذا كنت تملك خلفية PHP فيمكنك تعلم Laravel في غضون أسبوعين أو ثلاثة أسابيع، وهذه هي الوثائق الرسمية: وثائق Django ووثائق Laravel وثائق Rails. الأداء الأمن جميع هذه الأطر آمنة جدا إذا لم يرتكب المبرمج أخطاء، فيمتلك Django برمجيات وسيطة ويمتلك Rails Active Records وأما Laravel فيمتلك برمجيات HTTP وسيطة، وتوفر كل هذه الأطر رموز csrf للنماذج. لا يوجد فرق أمني كبير بين هذه الأطر، وكل هذا يعتمد على خبرة المبرمج. تحديث:أشار بعض القراء أن المبرمجين هم بشر وسيخطئون، لذا سأقول في هذه الحالة أن Django هو الأكثر أمانا وLaravel هو الأقل أمانًا، اطلع على هذا التوثيق عن أمن Django وهذا دليل أمن Rails و هذا دليل أمن Laravel، وسأقول أيضا أنه لا يوجد إطار آمن بشكل كامل لأن المطورين هم أيضا بشر، ويمكنك زيادة الأمن لكنك لا تستطيع جعله آمن بنسبة 100%، لكن إذا كتبت التعليمات البرمجية بعناية وحذر فإن جميع الأطر متساوية من ناحية الأمن. السرعة جميع الأطر مكتوبة بشكل صحيح، لذلك سرعتها تعتمد على اللغة البرمجة المستخدمة، فDjango هو الأسرع بسبب البايثون و Laravel هي الأبطأ بسبب PHP. الوقت المطلوب لإنشاء تطبيق إذا كنت تفهم الإطار بشكل كامل فإن إنشاء تطبيق Rails هو الأسرع لأنه يوفر لك الكثير من الاختصارات وبهذا ستكتب أقل عدد من الأسطر البرمجية. ومن جهة أخرى، Laravel هو الأبطأ ولا يوفر مكتبة قوية. إذا كان المشروع معقد فإن الفرق الزمني بين تطبيقات Django وRails سيكون صغيرًا بسبب صياغة بايثون المريحة للمتابعة وأقل أرباك، أما بالنسبة لـ Laravel فيجب عليك كتابة الكثير من الأسطر البرمجية وهذا قد يسبب لك بعض الإرباك وسترتفع نسبة الأخطاء. قوة وضعف المكتبة الأشياء المشتركة في جميع الأطر: جميعها MVC (يسمى Django MTV أيضا لكن على الرغم من أن الاسم مختلف إلا أن المفهوم هو نفسه). تركز جميع الأطر على قابلية القراءة وبساطة الشيفرة البرمجية وتوزيع الملفات. جميعها تستعلم تلقائيًا من قاعدة البيانات، فلا يجب عليك كتابة استعلامات قاعدة البيانات بشكل مباشر. تبنى الجداول تلقائيا في قاعدة البيانات من النماذج (models). جميع الأطر تملك نظام توجيه سهل وآمن، وتعرض صفحات الويب بشكل حيوي. تملك جميعها أنظمة قوالب خاصة بها وكل نظام قوالب غني بالمرشحات والدوال المعرّفة مسبقًا، الفرق الوحيد في الصياغة. جميعها مرنة ومحمولة مع تقنيات حديثة أخرى. Django يمتلك Django مكتبة قوية مع المميزات التالية: يعتبر قسم الإدارة المدمجة، المزخرف (decorator)، وأصناف المناظر نقاط قوة ل Django. الاستمارات المولدة تلقائيا للنماذج مع عملية التحقيق تجعلها سهلة للغاية. يدعم الإطار خاصية التخزين المؤقت وستتمكن من استخدام أي من أساليب التخزين المؤقت المتاحة. يدعم الأصناف البرمجيات الوسطيّة والتي يمكن أن تتدخّل في مراحل مختلفة من معالجة الطلب وتُنفّذ دوال مخصصة. يسمح لك نظام مرسل (dispatcher) داخلي لمكونات التطبيق اتصال الأحداث مع بعضها البعض عبر إشارات محددة مسبقا. يملك نظام تدويل يتضمن ترجمات لمكونات Django إلى لغات مختلفة. يملك نظام تسلسل الذي يمكنك من إنتاج وقراءة تمثيل XML و/أو JSON لمثيلات نموذج Django. واجهة بايثون مدمجة في إطار اختبار الوحدة. نظام مصادقة (authentication) موسّع. واجهة إدارة حيوية. أدوات لتوليد RSS وتغذيات (feed) خلاصات Atom. إطار مواقع تسمح ل Django واحد بتشغيل مواقع متعددة، ولكل منها المحتوى والتطبيقات الخاصة به. يملك أدوات لتوليد Google Sitemap. يملك تقنيات مدمجة للتخفيف من التزوير عبر الموقع، ثغرات XSS، ثغرات حقن SQL، تكسير كلمات المرور وهجمات الويب النموذجية، ومعظمها يعمل افتراضيا. إطار لإنشاء تطبيقات GIS. Laravel على الرغم من أن مكتبات Laravel ليست قوية مثل Django وRails إلا أنها كافية لإنشاء أي نوع من المواقع. يوفر Bundles و composer عدد من حزم نظام وحدات التحزيم والاعتماديات. التوجيه (Routing) – يوّفر طريقة سهلة وبسيطة لإدارة وتوجيه الروابط إلى متحكم أو دالة تُنفَّذ عند زيارة رابط محدَّد. دعم Eloquent ORM – خدمة أخرى مقدمة لتجريد وأتمتة جزء النموذج، حيث سنطبق التقنيات المتعارف عليها على الإعدادات. التهجيرات – طريقة لإصدار سكربتات قواعد البيانات بطريقة أنيقة للغاية، فلا حاجة للحفاظ على جميع التحققات على التهجيرات، يمكن لفريق عمل المشروع سحب الهجرة المقدمة وستعيّن جميعها وستكون جاهزة للعمل. إدارة قائمة الانتظار (Queue management) – لتجريد المهام غير الضرورية ووضعهم في قائمة الانتظار وجعل وقت استجابة المستخدم أسرع بكثير. دعم Redis، ويمكن توسيعها إلى memcached. حقن الإعتماديّة – اختبار سهل وأتمتة تحميل الإعتماديّة. Artisan – لإنشاء تطبيقات سطر الأوامر في لحظة. تعلم استخدام Laravel عن طريق هذه الدروس. Rails يتضمن Rails أدوات لجعل مهام التطوير الشائعة أسهل (خارج الصندوق)، مثل scaffolding الذي يستطيع إنشاء بعض النماذج تلقائيًا والمناظر اللازمة لموقع ويب الأساسي، بالإضافة إلى WEBrick وهو خادم ويب روبي بسيط الموزع مع روبي و Rake والذي هو نظام بناء موزع كـ gem. وتوفر هذه الأدوات جنبا إلى جنب مع Rails بيئة تطوير أساسية. Active record: يلعب دورا رئيسيا في تطبيقات Rails، وهو أفضل من Eloquent ORM في Laravel ومن النماذج في Django. اختصارات: يعبر الكثير من الناس الذين يأتون من لغات برمجة أو إطارات أخرى أن هذا الإطار سحري بسبب الاختصارات الكثيرة، فأغلب الأشياء معرّفة مسبقًا ويجب عليك كتابة بعض الأسطر البرمجية لإنشاء تطبيقات معقدة. التوجيه التلقائي: بعض الدوال الشائع في جدول قاعدة البيانات مثل الإنشاء ، التعديل والعرض مُعرّفة تلقائيًا، وهذا يعني أننا لا نحتاج إلى تضييع الوقت في المهام البسيطة ويمكننا قضاء وقت أطول على الأجزاء المعقدة من المشروع. سطر الأوامر: الكثير من الأشياء يمكن إنجازها عن طريق سطر الأوامر مثل استخدام rake وهي Ruby Make، أداة روبي مستقلة تستبدل أداة يونكس 'make' وتستخدم 'Rakefile' وملفات .rake لبناء قائمة مهام. في Rails، يُستخدم Rake لمهام الإدارة الشائعة، خاصة المعقدة منها التي تبني من بعضها البعض. تحتوي وحدة ActiveModelHelper على أساليب المساعدة لإنشاء النماذج من الكائنات بسرعة التي تتبع اتفاقيات Active Model، بداية من Active Record. خدمات الاستضافة يمكنك تشغيل أي تطبيق على VPS أو على خدمة استضافة مخصصة، وهذه مجموعة من الروابط لمواقع تسمح لك باستضافة مشروعك مجانا أو على خطط الاستضافة المشتركة. Django: بعض من المواقع التي تستضيف مشاريع Django هي: WebFaction، PythonAnywhere ، Heroku ، Digital Ocean ، Bulehost ، Dreamhost ، Arvixe و Google App Engine. Laravel: يمكنك الاستضافة على Heroku ، Bulehost ، Inmotion Hosting ، Site5 ، Dreamhost ، Digital Ocean و Arvixe. Rails: مواقع لتطبيقات Rails هي: Heroku ، Bulehost ، Dreamhost ، Arvixe ، Hosting24 و Digital Ocean. معايير أخرى كل هذه الأطر جيّدة في المستقبل، ففرص العمل، التكلفة والصيانة هي تقريبا نفسها ويمتاز Rails على Django وLaravel في شروط العمل، على الرغم من سرعة نمو Laravel. خاتمة يمكنك أن تختار أي واحدة من هذه الأطر حسب لغة البرمجة والخبرة، وإذا كنت هنا لتقرر أي واحدة يجب عليك تعلمها فأنا أفضل Rails، فعلى الرغم من صعوبة تعلمها إلا أنها مريحة أثناء إنشاء التطبيقات، إذا أردت أشياء سهلة مع الكثير من المميزات فاختر Django، فصياغة بايثون ونماذجه تجعله خيار جيدا، وعلى الرغم من أن تعلم Django قد يستغرق بعض الوقت إلا أنه ليس أصعب من Rails.إذا كانت لدي خبرة في PHP أو إذا أردت التعلم بسرعة فاختر Laravel. ترجمة -وبتصرّف- للمقال Django vs Laravel vs Rails لصاحبه Harish Kumar
  6. تابعنا في الدرس السابق من هذه السلسلة مرجع الارتباط المفصّل وسنتابع في هذا الدرس الحديث عن مرجع ارتباط has_one. 4.2 مرجع ارتباط has_one يُنشئ ارتباط has_one تطابق واحد لواحد (one-to-one) مع كائن آخر، بمصطلحات قاعدة البيانات، هذا الارتباط يعلن أن الصنف الآخر يحتوي على مفتاح خارجي، وإذا كان هذا الصنف يحتوي على مفتاح خارجي، فيجب عليك في هذه الحالة استخدام belongs_to بدلا من ذلك. 4.2.1 الأساليب المضافة بواسطة has_one عند إعلان ارتباط has_one، فإن الفئة المُعلنة ستحصل على 5 أساليب متعلقة بالارتباط: association (association=(associate ({} = build_association(attributes ({} = create_association(attributes ({} = create_association!(attributes reload_association في كل هذه الأساليب، يُستبدل الارتباط مع symbol المُمرر كمعامل أول إلى has_one، على سبيل المثال: class Supplier < ApplicationRecord has_one :account end فإن كل مثيل من نموذج Supplier سيحصل على هذه الأساليب: account account= build_account create_account create_account! reload_account 4.2.1.1 association يُرجع أسلوب association الكائن المرتبط إن وجد، وإلا، فسيرجع nil. @account = @supplier.account إذا أُسترد الكائن المرتبط بالفعل من قاعدة البيانات لهذا الكائن، ستٌسترجع النسخة المخبأة، ولتجاوز هذا السلوك(وإجبار قاعدة البيانات على القراءة)، استدعي #reload_association في الكائن الأب. @account = @supplier.reload_account 4.2.1.2 (association=(associate يُعيّن أسلوب =association كائن مرتبط إلى هذا الكائن، وفي ما وراء الكواليس، هذا يعني استخراج المفتاح الرئيسي من هذا الكائن وتعيين مفتاح الخارجي للكائن المرتبطة إلى نفس القيمة. @supplier.account = @account 4.2.1.3 ({} = build_association(attributes يرجع أسلوب build_association كائن جديد للنوع المرتبط، وهذا الكائن سيُنشئ من السمات المُمررة، وسيُعين الارتباط بمفتاحه الخارجي، لكن لن يُحفظ الكائن المرتبط. @account = @supplier.build_account(terms: "Net 30") 4.2.1.4 ({} = create_association(attributes يرجع أسلوب create_association كائن جديد من النوع المرتبط، وهذا الكائن سيُنشئ من السمات الممررة، وسيُعين الارتباط بمفتاحه الخارجي، وبمجرد النجاح في جميع التحقيقات (validations) المحددة في النموذج المرتبط، سيُحفظ الكائن المرتبط. @account = @supplier.create_account(terms: "Net 30") 4.2.1.5 ({} = create_association!(attributes يعمل كما create_association في الأعلى، لكنه يصدر ActiveRecord::RecordInvalid إذا كان السجل (record) غير صالح. 4-2-2 خيارات has_one في حين يستخدم Rails الافتراضات الذكية والتي تعمل بشكل جيد في أغلب الأحيان، لكن في بعض الأوقات ستحتاج إلى تخصيص سلوك مرجع ارتباط has_one، ويمكن تحقيق هذه التخصيصات بسهولة عن طريق تمرير الخيارات عند إنشاء الارتباط، فعلى سبيل المثال، يستخدم هذا الارتباط اثنين من هذه الخيارات: class Supplier < ApplicationRecord has_one :account, class_name: "Billing", dependent: :nullify end يدعم ارتباط has_one هذه الخيارات: as: autosave: class_name: dependent: foreign_key: inverse_of: primary_key: source: source_type: through: validate: 4.2.2.1 as: يشير تعيين خيار as: على أن الارتباط متعدد الأشكال، وستجد المزيد من التفاصيل حول الارتباطات متعددة الأشكال بالتفاصيل في الأعلى. 4.2.2.2 autosave: إذا عيّنت خيار autosave: إلى true، فإن Rails سيحفظ أي أعضاء محملين وسيدمر الأعضاء الذي وُضع عليهما علامة للتدمير كلما حفظت كائن الأب. 4.2.2.3 class_name: إذا لم يكن بالإمكان اشتقاق اسم النموذج الآخر من اسم الارتباط، يمكنك استخدام خيار class_name: لتوفير اسم النموذج، فعلى سبيل المثال، إذا كان المُورّد يمتلك حساب، لكن اسم النموذج الحالي الذي يحتوي على الحسابات هو Billing، فيمكنك فعل التالي: class Supplier < ApplicationRecord has_one :account, class_name: "Billing" end 4.2.2.4 dependent: يتحكم في ما يحدث للكائن المرتبط عند حذف مالكه: destroy: سيدمر كائن المرتبط أيضا. delete: سيحذف الكائن المرتبط مباشرة من قاعدة البيانات (ولن يعمل دوال الاستدعاء). nullify: سيُعين المفتاح الخارجي إلى NULL ولن يعمل دوال الاستدعاء. restrict_with_exception: سيصدر استثناء إذا كان هنالك كائن مرتبط. restrict_with_error: سيضاف خطأ إلى المالك إذا كان هنالك كائن مرتبط. من الضروري عدم تعيين أو ترك خيار nullify: للارتباطات التي تملك قيود NOT NULL على قاعدة البيانات، إذا لم تعيّن dependent لتدمير هذه الارتباطات فلن تتمكن من تغيير كائن المرتبط لأنه سيُعيّن المفتاح الخارجي للكائن المرتبط الأولي إلى NULL التي هي غير مسموح بها. 4.2.2.5 foreign_key: بالاتفاق، يفترض Rails أن العمود الذي يحمل المفتاح الخارجي في النموذج الآخر هو اسم النموذج مع إضافة بادئة id_، ويسمح لك خيار :foreign_key بتعيين اسم المفتاح الخارجي مباشرة: class Supplier < ApplicationRecord has_one :account, foreign_key: "supp_id" end 4.2.2.6 inverse_of: يحدد خيار inverse_of: اسم ارتباط belongs_to والذي هو عكس هذا الارتباط، وهذا الخيار لا يعمل في التركيبة مع خيارات through: أو as:. class Supplier < ApplicationRecord has_one :account, inverse_of: :supplier end class Account < ApplicationRecord belongs_to :supplier, inverse_of: :account end 4.2.2.7 primary_key: يفترض Rails أن العمود الذي يحمل المفتاح الرئيسي في هذا النموذج هو id، يمكنك تجاوز ذلك وتصريح المفتاح الرئيسي عن طريق خيار primary_key: 4.2.2.8 source: يحدد خيار source: اسم ارتباط المصدر لارتباط has_one :through. 4.2.2.9 source_type: يحدد خيار source_type: ارتباط المصدر لارتباط has_one :through الذي يمر عبر ارتباط متعدد الأشكال. 4.2.2.10 through: يحدد خيار through: نموذج الضم والذي يتم من خلاله تنفيذ الاستعلام، تم الحديث حول has_one :through في وقت سابق من هذا الدليل. 4.2.2.11 validate: إذا عُيّن خيار validate: إلى true، فسيتحقق من الكائنات المرتبطة كلما حفظت هذا الكائن، افتراضيا، قيمة هذا الخيار هي false، ولن يتحقق مع كائنات المرتبطة عند حفظ هذا الكائن. 4.2.3 نطاقات Scopes لـ belongs_to في بعض الأحيان قد تحتاج إلى تخصيص الاستعلام المُستخدم من قبل has_one، ويمكن تحقيق هذه التخصيصات عن طريق كتلة scope، فعلى سبيل المثال: class Supplier < ApplicationRecord has_one :account, -> { where active: true } end يمكنك استخدام أي من أساليب الاستعلامات القياسية داخل كتلة scope، وستجد تفاصيلها في الأسفل: where includes readonly select 4.2.3.1 where يسمح لك أسلوب where بتحديد شروط الكائن المرتبط. class Supplier < ApplicationRecord has_one :account, -> { where "confirmed = 1" } end 4.2.3.2 includes يمكنك استخدام أسلوب includes لتحديد الارتباطات من الدرجة الثانية التي تريد تحميلها (eager-loaded) عند استخدام هذا الارتباط، فعلى سبيل المثال، فكر في هذه النماذج: class Supplier < ApplicationRecord has_one :account end class Account < ApplicationRecord belongs_to :supplier belongs_to :representative end class Representative < ApplicationRecord has_many :accounts end إذا كنت تسترد الممثلين مباشرة من المُوردين بشكل كثير (supplier.account.representative@)، فيمكنك جعل شيفرتك البرمجية أكثر كفاءة من خلال تضمين الممثلين إلى الارتباط من المُوردين إلى الحسابات: class Supplier < ApplicationRecord has_one :account, -> { includes :representative } end class Account < ApplicationRecord belongs_to :supplier belongs_to :representative end class Representative < ApplicationRecord has_many :accounts end 4.2.3.3 readonly سيكون الكائن المرتبط للقراءة فقط عند استرداده عن طريق الارتباط إذا استخدمت readonly. 4.2.3.4 select يسمح لك أسلوب select بتجاوز جملة SELECT (في SQL) والتي تُستخدم لاسترداد البيانات حول الكائن المرتبط، وبشكل افتراضي، سيسترد Rails جميع الأعمدة. 4.2.4 هل توجد أية كائنات مرتبطة؟ يمكنك معرفة هل توجد أية كائنات مرتبطة عن طريقة استخدام أسلوب ?association.nil if @supplier.account.nil? @msg = "No account found for this supplier" end 4.2.5 متى تحفظ الكائنات؟ عند تعيين كائن إلى ارتباط has_one، سيُحفظ ذلك الكائن بشكل تلقائي (من أجل تحديث مفتاحه الخارجي)، بالإضافة إلى ذلك، يُحفظ أي كائن أُستبدل بشكل تلقائي لأن المفتاح الخارجي سيتغير أيضا. إذا فشلت عملية الحفظ بسبب أخطاء تحقق (validation)، فإن إعلان التعيين سيرجع false ويُلغى التعيين نفسه. إذا لم يُحفظ (سترجع ?new_record قيمة false) الكائن الأب (الذي يعلن ارتباطhas_one )، فإن الكائنات الأبناء لن يُحفظوا أيضا، وسيُحفظون تلقائيا عند حفظ الكائن الأب. إذا أردت تعيين كائن إلى ارتباط has_one بدون حفظ الكائن، استخدم أسلوب association.build. وسنتابع في الدرس القادم شرح مرجع ارتباط has_many (الأساليب المضافة والخيارات). المصدر: توثيقات Ruby on Rails
  7. ما هي لغة البرمجة التي يجب عليك تعلمها؟ بايثون، PHP أم روبي؟ ربما أكبر سؤال يواجه مطوري الويب المبتدئين هي ما هي أفضل لغة برمجة يجب تعلمها للوظيفة المستقبلية والآفاق، هنالك العديد من لغات البرمجة التي يجب عليك الاختيار منها وكل واحدة لديها نقاط القوة والضعف، ربما أهم مصدر مقلق هو المدة التي تستغرقه كل لغة للتعلم، وهذا يختلف من لغة إلى أخرى، فما الذي ينبغي تعلمه للحصول على أفضل وظيفة ناجحة في البرمجة؟ عندما بدأتُ تعلم تطوير الويب بحثتُ كثيرا حوله وجعلني هذا مرتبكًا بعض الشيء، فلم أتمكن من الحصول على إجابة نهائية حول ما هي أفضل لغة لأن كل كاتب له وجهة نظر مختلفة، وكان جميع الكتّاب يقارنون اللغات دون إعطاء استنتاج شامل. لذلك، في هذه المقالة، سأقارن بين اللغات البرمجة الحديثة الثلاثة، PHP وبايثون وروبي، وقبل كل شيء، أريد أن أظهر لك بعض البيانات القديمة التي وجدتها عندما بدأت بالتعلم حول تطوير الويب، وهذه البيانات القديمة مأخوذة من هنا وعلى الرغم من قِدَمِهَا إلا أنها تحتوي على بعض الحقائق المفيدة حول تاريخ هذه اللغات. بايثون ضد PHP ضد روبي من هذه المقارنة بين PHP وبايثون وروبي، ستجد أنه من الواضح: الطلب العالي على PHP في السوق. مبرمجي PHP مطلوبين بكثرة. قابلية استخدام PHP ضعيفة. تعلم واستخدام بايثون هو الأسهل. بايثون هي الأسرع. تعلم روبي هو الأصعب. يملك روبي أعلى قابلية استخدام. لكن كما قلت سابقًا، هذه مقارنة مختصرة، ومن هذه المقارنة لا يمكننا الاستنتاج أن PHP هو الأفضل وأن روبي هو الأسوأ، فهنالك أسئلة أخرى لم نرد عليها بعد. ما هي اللغة الأكثر أمانًا؟ ما هي القيود الأخرى على هذه اللغات؟ ما هي مزايا وأشكال الدعم الأخرى لهذه اللغات؟ ما هي نسبة وظيفة/مطور وما متوسط رواتب المطورين؟ ما هي اللغة الأكثر أمانا؟ يعتمد أمن الموقع/التطبيق في المقام الأول على المبرمج وليس لغة البرمجة، فمن المعروف أن PHP هي لغة برمجة غير آمنة، وهذا بسبب أن صياغة PHP ليست بسهولة صياغة بايثون أو روبي، وبسبب هذه الصياغة المعقدة (قابلية القراءة منخفضة) فإن فرص حدوث الأخطاء أكبر. فإذا كان المبرمج/المطور لا يخطئ، فليست PHP لغة غير آمنة، وفي الواقع، لدى PHP5 سمعة طيّبة مقارنة بالإصدارات القديمة، وكنتيجة لذلك، لا يوجد في الواقع استنتاج قوي حول مسألة أمن اللغة. ما هي قيود هذه اللغات؟ PHP: يملك الكثير من الصيغ المطولة من C++/C وبيرل، مع الكثير من الأقواس المعقوفة وعلامات الدولار و “→”. جدول مربك لأسماء الدوال، فتمتلك المكتبة المدمجة مجموعة كبيرة من اتفاقيات التسمية، ويملك الدوال في العادة على بادئة للدلالة على مصدرها (ولكنها لا تمتلك ذلك في كثير من الأحيان). تكون الدوال في العادة في أصناف لمحاكاة مساحات الأسماء (namespace). ليست مناسبة للتطبيقات الكبيرة: صعوبة الصيانة لأنها لا تتكون من وحدات بشكل جيّد. نوع ضعيف: التحويل الضمني قد يفاجئ المبرمجين الغافلين ويؤدي إلى أخطاء غير متوقعة، على سبيل المثال، تتساوى السلاسل “1000” و“1e3” عند المقارنة لأنها تحوّل ضمنيا إلى أعداد كسرية. لغة برمجة سكربتية، ليست لغة برمجة كائنية التوجه. بايثون: لا تملك بيان ‘switch’ ولا هيكل ‘do … while’. عوامل الزيادة والنقصان والتعيين (التعيين هو بيان فقط في بايثون). العامل/البيان الثلاثي (… ? … : …). بيئة مناسبة (مثبتة عادة). لا توجد مبدلات (modifier) خاصة، محمية و عامة للخصائص والأساليب. لا تملك abstract ومبدلات نهائية للأصناف والأساليب. روبي: قد تكون صعبة التعلم. تفتقر إلى موارد المعلومات. وقت المعالج بطيء (وقت CPU) بالمقارنة مع لغات برمجة أخرى. التطوير والتحديث أبطأ. ما هي مزايا وأشكال الدعم الأخرى لهذه اللغات؟ PHP: سهلة التعلم للمبتدئين وللمطورين القادمين من لغات ذات صياغة مشابهة مثل C و C++ و C# وجافا وجافا سكربت، إلخ. تدعم جميع خوادم ويب الرئيسية مثل اباتشي، مايكروسوفت IIS، Netscape و الخوادم الشخصية و خادم iPlanet… الخ. مقبولة للغاية من قبل صناعات عديدة وهي أكثر شعبيّة من بقية لغات البرمجة. سهولة استضافة PHP مباشرة دون أي إعدادات للخادم لأن استضافة المواقع صعبة بالنسبة للمبتدئين. يعتبر إطار zend هو الأشهر في PHP، وبعض الأطر الأخرى مثل Yii وLaravel وCodeigniter أعطت قوة كبيرة لـ PHP. من السهل تطوير أي نوع من CMS بسرعة. بايثون: سهولة الصياغة والقراءة، وسهلة التعلم للذين لا يمتلكون خبرة في البرمجة. لغة برمجة أغراض عامة. لغة برمجة كائنية التوجه. بايثون مناسبة جدا لـ glue. مكتبة قياسية ضخمة، كمثال عشوائي، تملك بايثون محللين لـ XML، قراء وكتّاب لملفات zip وcsv، مكتبات لاستخدام كل بروتوكول إنترنت ونوع بيانات، الخ. هياكل بيانات متطور كالقوائم والقواميس. أطر كبيرة لتطوير الويب مثل جانغو وFlask. روبي: تعتبر روبي لغة كائنية التوجه أكثر من بايثون وPHP. تم تطوير روبي لجعل عمل المطور سهل. تسمح الإضافات الأصناف والوحدات المستدعية بالتوسع والتغيير عن طريق الشيفرة البرمجية الخاصة بالمستخدمة بعد استدعائها، فالأصناف لا تغلق في روبي، حيث يمكنك تغييرها لاحقا. كتل الشيفرة البرمجية الخاصة بروبي أقوى من lambda الخاص ببايثون. كل شيء يرجع قيمة (بما في ذلك بيان ‘if’) ، وبسبب هذا، من السهل كتابة شيفرة برمجية مشابهة للدالة مقارنة بالبايثون وأسهل عند سلسلة الأوامر. مكتبات Gem الخاصة بالروبي، فالكثير من gem المتاحة تجعل فعل أي مهمة سهلةً بأقل جهد. قوة روبي في تطوير الويب هو إطار ريلز، فهو سحري جدًا، فلن تحتاج إلى القلق بشأن الوظائف الأساسية لتطوير الويب مثل التعديل والحذف البسيط، بل يمكنك التركيز على الخوارزميات المعقّدة الأخرى. يعتقد الروبي في إعطاء المبرمج الحرية والقوة. ما هي نسبة وظيفة/مطور وما متوسط رواتب المطورين؟ هذا السؤال شخصي للغاية ولن تكون له إجابة عامة بسيطة، فأغلب الوظائف والمبرمجين يستخدمون PHP، وأدى هذا إلى ضعف الرواتب بصفة عامة، ومع ذلك، فهذا لا يعني أن رواتب جميع المطورين/المبرمجين ضعيف، فبعض المطورين يحصلون على أموالٍ كثيرةٍ. هنالك فرص عمل كثيرة لمبرمجي بايثون وروبي بما أنهم يمتلكون عدد قليل من المبرمجين، لكن الطلب أقل في العادة. استنتاج عام: دعونا نلخص كل هذا باختصار: PHP وبايثون سهل التعلم بالنسبة للمبتدئين. PHP هي الأكثر طلبًا في العمل. PHP جيّدة للمواقع الصغيرة. (على الرغم من أن هنالك الكثير من المواقع الكبيرة مثل فيسبوك و ويكيبيديا مكتوبة بلغة PHP لكن ضمّن إليها لغات أخرى. تغيير موقع من لغة برمجة إلى لغة أخرى ليست مهمة سهلة). بايثون هي أفضل لغة للأغراض العامة. تُفضل إطارات بايثون (جانغو) وروبي (ريلز) أكثر من أي إطار آخر لبرمجة الويب. يمكنك اختيار أي واحدة منهم، فإذا لم تكن تبحث عن هدف كبير فبايثون هي الأفضل ليس فقط بسهولة تعلمها بل لأنها للأغراض العامة وتملك العديد من المميزات الكبيرة مثل هياكل البيانات، لكن جميع لغات البرمجة لديها نطاقات خاصة بها مثل اللاعبين في أي لعبة. ترجمة -وبتصرّف- للمقال PYTHON vs PHP vs RUBY لصاحبه Harish Kumar
  8. هذا هو دليل Airbnb لنمط روبي. مستوحى من دليل GitHub ودليل Bozhidar Batsov. المسافات البيضاء المسافة الفارغة استخدم علامات التبويب (tabs) ذات المسافتين. يكون عمق when بقدر عمق case. case when song.name == 'Misty' puts 'Not again!' when song.duration > 120 puts 'Too long!' when Time.now.hour > 21 puts "It's too late" else song.play end kind = case year when 1850..1889 then 'Blues' when 1890..1909 then 'Ragtime' when 1910..1929 then 'New Orleans Jazz' when 1930..1939 then 'Swing' when 1940..1950 then 'Bebop' else 'Jazz' end ترصيف معاملات الدالة إما على نفس السطر أو سطر واحد لكل واحدة. # bad def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # good def self.create_translation(phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification) ... end # good def self.create_translation( phrase_id, phrase_key, target_locale, value, user_id, do_xss_check, allow_verification ) ... end ضع علامة التبويب في التعبيرات المنطقية متعددة السطور. # bad def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end # good def is_eligible?(user) Trebuchet.current.launch?(ProgramEligibilityHelper::PROGRAM_TREBUCHET_FLAG) && is_in_program?(user) && program_not_expired end على السطر لا تترك مسافة فارغة زائدة. عند تضمين التعليقات في السطر، اترك مسافة واحدة بين نهاية الشيفرة البرمجية وبداية تعليقك. # bad result = func(a, b)# we might want to change b to c # good result = func(a, b) # we might want to change b to c استخدم المسافات حول العوامل (operators)، أي بعد الفواصل، بعد النقطتين، الفاصلة المنقوطة، وبعد { وقبل }. sum = 1 + 2 a, b = 1, 2 1 > 2 ? true : false; puts 'Hi' [1, 2, 3].each { |e| puts e } لا تضع مسافة قبل الفاصلة. result = func(a, b) لا تضع مسافة دخل أنابيب (pipe) كتلة المعاملات، بل ضع واحد بين المعاملات في الكتلة وواحدة خارج أنابيب كتلة المعاملات. # bad {}.each { | x, y |puts x } # good {}.each { |x, y| puts x } لا تضع فراغات بين ! ومعاملاتها. !something لا تترك فارغات بعد (، [ وقبل )، ]. some(arg).other [1, 2, 3].length تجنب وضع المسافات عند استيفاء السلاسل النصية. # bad var = "This #{ foobar } is interpolated." # good var = "This #{foobar} is interpolated." لا تستخدم مسافة إضافية في النطاق الحرفي. # bad (0 ... coll).each do |item| # good (0...coll).each do |item| أسطر جديدة أضف سطر جديد بعد شروط if لكي تكون في عدة أسطر ولتساعد في التفريق بين الشروط والجسم. if @reservation_alteration.checkin == @reservation.start_date && @reservation_alteration.checkout == (@reservation.start_date + @reservation.nights) redirect_to_alteration @reservation_alteration end أضف سطر جديد بعد الشروط، الكتل، البيانات، إلخ… if robot.is_awesome? send_robot_present end robot.add_trait(:human_like_intelligence) لا تضع أسطر جديدة بين مناطق مسافات البادئة المختلفة (مثلا حول أجزاء الصنف أو الوحدة). # bad class Foo def bar # body omitted end end # good class Foo def bar # body omitted end end أضف سطر جديد واحد فقط بين الأساليب. def a end def b end استخدم سطر فارغ واحد للكسر بين البيانات لتقسيم الأساليب إلى فقرات منطقية داخليًا. def transformorize_car car = manufacture(options) t = transformer(robot, disguise) car.after_market_mod! t.transform(car) car.assign_cool_name! fleet.add(car) car end ضع سطر فارغ في نهاية كل ملف، ولا تضع أكثر من سطر فارغ. طول السطر اجعل كل سطر قابل للقراءة، ما لم يكن لديك سبب معين، ابقي طول الأسطر أقل من 100 حرف (أساس منطقي). التعليقات على الرغم من أن التعليقات متعبة عند كتابتها، إلا أنها مفيدة للغاية لإبقاء شيفرتك البرمجية قابلة للقراءة، وتصف القواعد التالية ما يجب التعليق عليه وأين، لكن تذكر: على الرغم أن التعليقات مهمة جدًا إلا أن أفضل شيفرة برمجية هي التي توثق ذاتها، فإعطاء أسماء معقولة للأنواع والمتغيرات أفضل بكثير من استخدام أسماء غامضة يجب عليك شرحها من خلال التعليقات. عند كتابة تعليقاتك، اكتب للجمهور: المساهم التالي سيحتاج إلى فهم شيفرتك البرمجية، كن سخيًا، فالتالي قد يكون أنت! تعليقات ملف/مستوى الصنف يجب أن يكون لكل تعريف صنف تعليق مصاحب يصف ما هو وكيف يُستخدم. يجب أن يملك الملف الذي لا يحتوي على أصناف أو يحتوي على أكثر من صنف واحد على تعليق في أعلاه يصف محتوياته. # Automatic conversion of one locale to another where it is possible, like # American to British English. module Translation # Class for converting between text between similar locales. # Right now only conversion between American English -> British, Canadian, # Australian, New Zealand variations is provided. class PrimAndProper def initialize @converters = { :en => { :"en-AU" => AmericanToAustralian.new, :"en-CA" => AmericanToCanadian.new, :"en-GB" => AmericanToBritish.new, :"en-NZ" => AmericanToKiwi.new, } } end ... # Applies transforms to American English that are common to # variants of all other English colonies. class AmericanToColonial ... end # Converts American to British English. # In addition to general Colonial English variations, changes "apartment" # to "flat". class AmericanToBritish < AmericanToColonial ... end يجب أن تملك جميع الملفات بما في ذلك ملفات البيانات والتهيئة، على تعليقات على مستوى الملف. # List of American-to-British spelling variants. # # This list is made with # lib/tasks/list_american_to_british_spelling_variants.rake. # # It contains words with general spelling variation patterns: # [trave]led/lled, [real]ize/ise, [flav]or/our, [cent]er/re, plus # and these extras: # learned/learnt, practices/practises, airplane/aeroplane, ... sectarianizes: sectarianises neutralization: neutralisation … تعليقات الدالة يجب أن يكون لكل إعلان دالة تعليقات تسبقها مباشرة تصف ما تقوم به الدالة وكيفية استخدامها، ويجب أن تكون هذه الملفات وصفية (‘تفتح الملف’) بدلا من أمرية (‘افتح الملف’). التعليقات التي تصف الدالة، لا تقول ما تقوم به الدالة، بشكل عام، هذه التعليقات لا تصف كيفية عمل الدالة، وبدلا من ذلك، يجب ترك هذه للتعليقات التي تتخلل الشيفرة البرمجية للدالة. يجب أن تذكر كل دالة ما هي المدخلات وما هي المخرجات، ما لم تستوف جميع المعايير التالية: غير مرئية من الخارج قصيرة جدا واضحة يمكنك استخدام أي تنسيق تريده، في الروبي، يوجد مخططين لتوثيق الدالة وهما TomDoc وYARD. يمكنك كتابة الأشياء بشكل موجز: # Returns the fallback locales for the_locale. # If opts[:exclude_default] is set, the default locale, which is otherwise # always the last one in the returned list, will be excluded. # # For example: # fallbacks_for(:"pt-BR") # => [:"pt-BR", :pt, :en] # fallbacks_for(:"pt-BR", :exclude_default => true) # => [:"pt-BR", :pt] def fallbacks_for(the_locale, opts = {}) ... end الكتلة والتعليقات المضمّنة المكان النهائي للتعليقات هو في الأجزاء الصعبة من التعليمات البرمجية، فعّلق عليها الآن إذا كان يجب عليك شرحها عند مراجعة الشيفرة البرمجية. يجب أن تحصل العمليات المعقدة على بضعة أسطر من التعليقات قبل بدء العمليات، بالنسبة للأجزاء الغير واضحة تحصل على تعليقات في نهاية السطر. def fallbacks_for(the_locale, opts = {}) # dup() to produce an array that we can mutate. ret = @fallbacks[the_locale].dup # We make two assumptions here: # 1) There is only one default locale (that is, it has no less-specific # children). # 2) The default locale is just a language. (Like :en, and not :"en-US".) if opts[:exclude_default] && ret.last == default_locale && ret.last != language_from_locale(the_locale) ret.pop end ret end من ناحية أخرى، لا تصف شيفرتك البرمجية، افترض أن الشخص الذي يقرأ شيفرتك البرمجية يعرف لغة البرمجة (وإن لم يكن ما تحاول القيام به) أفضل منك. وعلى سياق متصل: لا تستخدم كتل التعليقات، فلا يمكن أن تسبقها بمسافة وليس من السهل رؤيتها كالتعليقات المنتظمة. # bad =begin comment line another comment line =end # good # comment line # another comment line علامات الترقيم، الإملاء والنحو اهتم بعلامات الترقيم، الإملاء والنحو، فمن السهل قراءة التعليقات المكتوبة بشكل جيد من تلك المكتوبة بشكل سيء. ينبغي أن تكون التعليقات قابلة للقراءة كنص سردي، مع وجود الأحرف الكبيرة وعلامات الترقيم. في حالات كثيرة، الجمل الكاملة هي الأكثر قابلية للقراءة من جمل القصيرة. يمكن للتعليقات القصيرة، كالتعليقات في نهاية سطر شيفرة برمجية، أن تكون أقل رسمية، لكن يجب أن تكون متسقة مع نمطك. على الرغم من أنه من المحبط أن يشير مُراجِع شيفرتك البرمجية إلى أنك تستخدم فاصلة في مكان الفاصلة المنقوطة، لذا من المهم أن تحافظ شيفرتك البرمجية على مستوى عال من الوضوح وقابلية القراءة، وتساعد علامة الترقيم، الإملاء والنحو في تحقيق هذا الهدف. تعليقات TODO استخدم تعليقات TODO للشيفرات البرمجية المؤقتة، حل قصير الأجل أو جيد بما يكفي ولكن ليس مثال. يجب أن تتضمن TODO كلمة TODO بالأحرف الكبيرة متبوعة باسم الكامل للشخص الذي يمكنه توفير أفضل سياق حول المشكلة المشار إليها من قبل TODO بين قوسين. يمكنك إضافة النقطتين ومن ثم ضع تعليق يشرح ما يجب القيام به، فالغرض الرئيسي و أن يكون تنسيق TODO قابل للبحث لإيجاد الشخص الذي يمكنه توفير المزيد من التفاصيل عند الطلب، فـ TODO ليس التزاما من الشخص المشار إليه لإصلاح المشكلة، وبالتالي عند إنشاء TODO، تكتب في الغالب اسمك. # bad # TODO(RS): Use proper namespacing for this constant. # bad # TODO(drumm3rz4lyfe): Use proper namespacing for this constant. # good # TODO(Ringo Starr): Use proper namespacing for this constant. شيفرات برمجية بدون تعليقات لا تترك شيفرات برمجية بدون تعليقات في قاعدة الشيفرات البرمجية الخاصة بنا. الأساليب تعريف الأساليب استخدم def مع الأقواس عند وجود معاملات، واحذف الأقواس عندما لا يقبل الأسلوب المعاملات. def some_method # body omitted end def some_method_with_parameters(arg1, arg2) # body omitted end لا تستخدم المعاملات الموضعية الافتراضية، بل استخدم معاملات الكلمات الرئيسية (keyword) – إذا كانت موجودة، في الإصدار 2 من روبي أو أحدث - أو hash من الخيارات. # bad def obliterate(things, gently = true, except = [], at = Time.now) ... end # good def obliterate(things, gently: true, except: [], at: Time.now) ... end # good def obliterate(things, options = {}) options = { :gently => true, # obliterate with soft-delete :except => [], # skip obliterating these things :at => Time.now, # don't obliterate them until later }.merge(options) ... end تجنب الأساليب المتكونة من سطر واحد، على الرغم من انتشارها، إلا أنه توجد بعض الخصوصيات حول صياغتها تجعل استخدامها غير مرغوب فيه. # bad def too_much; something; something_else; end # good def some_method # body end دوال الاستدعاء استخدم الأقواس لدالة الاستدعاء: • إذا كانت الدالة ترجع قيمة. # bad @current_user = User.find_by_id 1964192 # good @current_user = User.find_by_id(1964192) إذا كان المعامل الأول إلى الدالة يستخدم الأقواس. # bad put! (x + y) % len, value # good put!((x + y) % len, value) لا تضع أبدًا مسافة بين اسم الدالة والقوس الأول. # bad f (3 + 2) + 1 # good f(3 + 2) + 1 تجنب الأقواس عند استدعاء الدالة إذا لم يكن يقبل أية معاملات. # bad nil?() # good nil? ستكون الأقواس اختيارية إذا لم تكن الدالة ترجع قيمة (أو لا نهتم بما ترجعه)، خاصة إذا كانت المعاملات في عدة أسطر، فالأقواس ستزيد من قابلية القراءة. # okay render(:partial => 'foo') # okay render :partial => 'foo' في كلا الحالتين: في حالة قبول الدالة لـ hash من الخيارات كمعامل أخير، لا تستخدم { } أثناء الاستدعاء. # bad get '/v1/reservations', { :id => 54875 } # good get '/v1/reservations', :id => 54875 التعبيرات الشرطيّة الكلمات الرئيسية المشروطة لا تستخدم then لـ if/unless متعددة الأسطر. # bad if some_condition then ... end # good if some_condition ... end لا تستخدم do لـ while أو until متعددة الأسطر. # bad while x > 5 do ... end until x > 5 do ... end # good while x > 5 ... end until x > 5 ... end إن الكلمات الرئيسية and وor وnot محظورة، فهي لا تستحق العناء، استخدم && و || و ! بدلا منها. يمكنك استخدام المعدِل if/unless عندما يكون الجسم بسيط، الشرط بسيط وكل شيء في سطر واحد، وخلافًا لذلك، تجنب استخدام if/unless. # bad - this doesn't fit on one line add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? # okay if request_opts[:trebuchet_experiments_on_page] && !request_opts[:trebuchet_experiments_on_page].empty? add_trebuchet_experiments_on_page(request_opts[:trebuchet_experiments_on_page]) end # bad - this is complex and deserves multiple lines and a comment parts[i] = part.to_i(INTEGER_BASE) if !part.nil? && [0, 2, 3].include?(i) # okay return if reconciled? لا تستخدم أبدًا unless مع else، أعد كتابتها مع الحالة الصحيحة الأولى أولًا. # bad unless success? puts 'failure' else puts 'success' end # good if success? puts 'success' else puts 'failure' end تجنب unless مع شروط متعددة. # bad unless foo? && bar? ... end # okay if !(foo? && bar?) ... end تجنب استخدام unless مع عامل مقارنة إذا كان يمكنك استخدام if مع عامل المقارنة المعاكس. # bad unless x == 10 ... end # good if x != 10 ... end # bad unless x < 10 ... end # good if x >= 10 ... end # ok unless x === 10 ... end لا تستخدم أقواس حول شرط if/unless/while. # bad if (x > 10) ... end # good if x > 10 ... end العامل الثلاثي تجنب استخدام العامل الثلاثي (?:) إلا في الحالات التي تكون فيها جميع التعبيرات بسيطة، ومع ذلك لا تستخدمه بدلا من if/then/else/end في الشروط المتكونة من سطر واحد. # bad result = if some_condition then something else something_else end # good result = some_condition ? something : something_else استخدم تعبير واحد لكل فرع في العامل الثلاثي، كذلك لا يجب أن يكون العامل الثلاثي متداخِلا، حيث يُفضّل استخدام بنية if/else في هذه الحالات. # bad some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else # good if some_condition nested_condition ? nested_something : nested_something_else else something_else end تجنب الشروط المتعدّدة في العامل الثلاثي حيثُ يُفضّل استخدام الأخير مع الشروط الفردية. تجنب الأسطر المتعدّدة ?: (العامل الثلاثي)، واستخدم if/then/else/end بدلا منه. # bad some_really_long_condition_that_might_make_you_want_to_split_lines ? something : something_else # good if some_really_long_condition_that_might_make_you_want_to_split_lines something else something_else end الشروط المتداخلة تجنب استخدام الشروط المتداخلة لتدفق السيطرة. يُفضّل استخدام شرط الحراسة (guard clause) عندما يمكنك تأكيد بيانات غير صالحة، فشرط الحراسة هو عبارة مشروطة في أعلى الدالة التي ترّجع في أسرع ما يمكن. المبادئ العامة هي: إرجاع الفوري بمجرد معرفة أن الدالة لا يمكنها أن تفعل أي شيء أكثر من الذي فعلته. تقليل التداخل ومسافة البادئة في الشيفرة البرمجة عن طريق الإرجاع في وقت مبكّر. وهذا يجعل الشيفرات برمجية أسهل للقراءة وتطلّب أقل جهد عقلي في الجزء القراءة عند تتبّع فروع أخرى. ينبغي أن تكون التدفقات الجوهرية أو الأكثر أهمية هي الأقل مسافات البادئة. # bad def compute server = find_server if server client = server.client if client request = client.make_request if request process_request(request) end end end end # good def compute server = find_server return unless server client = server.client return unless client request = client.make_request return unless request process_request(request) end يُفضّل استخدام next في الحلقات بدلا من الكتل الشرطيّة. # bad [0, 1, 2, 3].each do |item| if item > 1 puts item end end # good [0, 1, 2, 3].each do |item| next unless item > 1 puts item end الصياغة لا تستخدم for إلا إذا كنت تعرّف السبب بالضبط، ففي أغلب الأحيان، يجب استخدام التكرارات (iterator) بدلا منها، فتعمل for بنفس شروط each (أي أنك ستضيف مستوى من المراوغة) لكن مع عيب صغير، فلا تُعرّف for نطاق جديد (على عكس each) وستظهر المتغيرات المعرّفة في كتلتها خارجها. arr = [1, 2, 3] # bad for elem in arr do puts elem end # good arr.each { |elem| puts elem } يفضل استخدام {...} بدلا من do...end للكتل المتكونة من سطر واحد، وتجنّب استخدام {...} للكتل المتكونة من عدة أسطر (فسلسلة عدة أسطر هو شيء قبيح)، واستخدم do...end دائما للتحكم في التدفّق وتعريف الأساليب (على سبيل المثال في Rakefile وفي بعض DSL) وتجنب استخدام do...end عند السلّسلة. names = ["Bozhidar", "Steve", "Sarah"] # good names.each { |name| puts name } # bad names.each do |name| puts name end # good names.each do |name| puts name puts 'yay!' end # bad names.each { |name| puts name puts 'yay!' } # good names.select { |name| name.start_with?("S") }.map { |name| name.upcase } # bad names.select do |name| name.start_with?("S") end.map { |name| name.upcase } سيجادلنا البعض ويقول أن السلّسلة للأسطر المتعددة تبدوا جيّدة عند استخدام {...}، لكن هل سُئلوا أنفسهم هل أن هذه الشيفرة البرمجية قابلة للقراءة حقا وما إذا كان يمكن استخلاص محتوى الكتلة إلى أساليب فعّالة. استخدام عوامل التعيين المختصرة كلما كان ذلك ممكنا. # bad x = x + y x = x * y x = x**y x = x / y x = x || y x = x && y # good x += y x *= y x **= y x /= y x ||= y x &&= y تجنب الفواصل المنقوطة باستثناء للتعريفات صنف السطر الواحد، وعندما يكون من الملائم استخدام فاصلة منقوطة، ينبغي أن تكون متاخمة مباشرةً للبيان الذي تنهيه: لا يجب أن يكون هنالك مسافة قبل الفاصلة المنقوطة. # bad puts 'foobar'; # superfluous semicolon puts 'foo'; puts 'bar' # two expressions on the same line # good puts 'foobar' puts 'foo' puts 'bar' puts 'foo', 'bar' # this applies to puts in particular استخدم :: للثوابت المرجعيّة فقط(ويشمل هذا الأصناف والوحدات) والبنائين (مثل Array() أو Nokogiri::HTML()) ولا تستخدم :: لاستدعاء الأسلوب العادي. # bad SomeClass::some_method some_object::some_method # good SomeClass.some_method some_object.some_method SomeModule::SomeClass::SOME_CONST SomeModule::SomeClass() تجنب استخدام return عندما تكون غير مطلوبة. # bad def some_method(some_arr) return some_arr.size end # good def some_method(some_arr) some_arr.size end لا تستخدم القيمة المُرجّعة من = في الجمل الشرطيّة. # bad - shows intended use of assignment if (v = array.grep(/foo/)) ... end # bad if v = array.grep(/foo/) ... end # good v = array.grep(/foo/) if v ... end استخدم ||= كما تريد لتهيئة المتغيرات. # set name to Bozhidar, only if it's nil or false name ||= 'Bozhidar' لا تستخدم ||= لتهيئة المتغيرات المنطقيّة، (فكر في ما سيحدث إذا كانت القيمة الحالية تساوي false). # bad - would set enabled to true even if it was false enabled ||= true # good enabled = true if enabled.nil? استخدم .call الصريحة عند استدعاء lambda. # bad lambda.(x, y) # good lambda.call(x, y) تجنب استخدام متغيرات الخاصة على نمط بيرل (مثل $0-9، KaTeX parse error: Expected 'EOF', got '،' at position 1: ،̲ الخ)، فهي مشفّ…PROGRAM_NAME`. استخدم الاختصار &: عندما تأخذ كتلة الأسلوب معامل واحد فقط ويعمل الجسم على قراءة سمة أو استدعاء أسلوب دون معاملات. # bad bluths.map { |bluth| bluth.occupation } bluths.select { |bluth| bluth.blue_self? } # good bluths.map(&:occupation) bluths.select(&:blue_self?) يفضل استخدام some_method على self.some_method عند استدعاء دالة في المثيل الحالي. # bad def end_date self.start_date + self.nights end # good def end_date start_date + nights end في هذه الحالات الثلاثة، يجب عليك استخدام self. : عند تعريف أسلوب صنف: def self.some_method. عندما تكون self هي نموذج ActiveRecord ويكون الجانب الأيسر هو استدعاء أسلوب تعيين بما في ذلك تعيين سمة: self.guest = user. الإشارة إلى صنف مثيل الحالي: self.class. عند تعريف كائن من أي نوع قابل للتحويل وتريده أن يكون ثابت، تأكد من استدعاء freeze عليه، ومن الأمثلة الشائعة على ذلك هي السلاسل النصية، المصفوفات، وhash. سبب ذلك أن ثوابت روبي هي أنواع قابلة للتحويل، وستتأكد من عدم قابليتهم للتحويل عند استدعاء freeze عليهم لأنه سيصدر استثناء عند محاولة تعديلهم ، وبالنسبة إلى السلاسل النصية، سيسمح هذا بالتعامل معهم لنسخ روبي الأقدم من 2.2. # bad class Color RED = 'red' BLUE = 'blue' GREEN = 'green' ALL_COLORS = [ RED, BLUE, GREEN, ] COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, } end # good class Color RED = 'red'.freeze BLUE = 'blue'.freeze GREEN = 'green'.freeze ALL_COLORS = [ RED, BLUE, GREEN, ].freeze COLOR_TO_RGB = { RED => 0xFF0000, BLUE => 0x0000FF, GREEN => 0x00FF00, }.freeze end التسمية استخدم snake_case للأساليب والمتغيرات. استخدم حالة الجمل (CamelCase) للأصناف والوحدات. (احتفظ بالاختصارات مثل HTTP وRFC وXML بحالة أحرف كبيرة). استخدم SCREAMING_SNAKE_CASE للثوابت الأخرى. يجب أن تنتهي الأساليب الإسنادية (التي ترجع قيمة منطقية) بعلامة استفهام. (على سبيل المثال Array#empty?). يجب أن تنتهي أسماء الأساليب التي يُحتمل أن تكون خطرة (مثل الأساليب التي تعدل self أو المعاملات، exit!، الخ) بعلامة تعجب، ويجب أن تتواجد الأساليب الخطرة (bang) إذا لم تتواجد الأساليب غير الخطرة (non-bang) - للمزيد من المعلومات -. سمّي متغيرات الرمي (throwaway) _. version = '3.2.1' major_version, minor_version, _ = version.split('.') الأصناف تجنب استخدام متغيرات (@@) بسبب سلوكهم السيئ في الميراث. class Parent @@class_var = 'parent' def self.print_class_var puts @@class_var end end class Child < Parent @@class_var = 'child' end Parent.print_class_var # => will print "child" كما ترى أنه جميع الأصناف في التسلسل الهرمي للصنف تتشارك في متغير صنف واحد، ويجب أن تُفضّل متغيرات مثيل الصنف على متغيرات الصنف. استخدم def self.method لتعريف الأساليب المنفردة، وسيجعل هذا الأساليب أكثر مقاومة لتغييرات إعادة الهيكلة. class TestClass # bad def TestClass.some_method ... end # good def self.some_other_method ... end • تجنب استخدام `class << self` إلا عند الضرورة، على سبيل المثال، موصول مفرد (`single accessors`) وسمات مستعارة (`aliased attributes`). class TestClass # bad class << self def first_method ... end def second_method_etc ... end end # good class << self attr_accessor :per_page alias_method :nwo, :find_by_name_with_owner end def self.first_method ... end def self.second_method_etc ... end end ضع مسافة البادئة للأساليب public، protected وprivate بقدر تعريف الأسلوب الذي ينتمون إليه، واترك سطر فارغ واحد أعلاهم وأسفلهم. class SomeClass def public_method # ... end private def private_method # ... end end الاستثناءات لا تستخدم الاستثناءات لتدفق التحكم. # bad begin n / d rescue ZeroDivisionError puts "Cannot divide by 0!" end # good if d.zero? puts "Cannot divide by 0!" else n / d end تجنب إنقاذ (rescue) صنف Exception. # bad begin # an exception occurs here rescue Exception # exception handling end # good begin # an exception occurs here rescue StandardError # exception handling end # acceptable begin # an exception occurs here rescue # exception handling end لا تحدد RuntimeError في نسخة المعاملين من raise، ومن الأفضل استخدام خطأ الأصناف الفرعية من أجل الوضوح وشرح خطأ بشكل أفضل. # bad raise RuntimeError, 'message' # better - RuntimeError is implicit here raise 'message' # best class MyExplicitError < RuntimeError; end raise MyExplicitError يُفضّل توفير صنف استثناء والرسالة كمعاملين إلى raise بدلا من مثيل استثناء. # bad raise SomeException.new('message') # Note that there is no way to do `raise SomeException.new('message'), backtrace`. # good raise SomeException, 'message' # Consistent with `raise SomeException, 'message', backtrace`. تجنب استخدام rescue في شكل المُعدّل. # bad read_file rescue handle_error($!) # good begin read_file rescue Errno:ENOENT => ex handle_error(ex) end المجموعات Collections يفضّل استخدام map على collect. يفضّل استخدام detect على find، فاستخدام find غامض بسبب أسلوب find الخاصة بـ ActiveRecord وسيُظهر detect على أنك تعمل مع مجموعة روبي وليس كائن AR. يُفضّل استخدام reduce على inject. يُفضّل استخدام size على length و count لأسباب تتعلّق بالأداء. يفّضل استخدام تدوين الإنشاء (creation notation) للمصفوفة الحرفيّة وللـ hash إلا إذا كنت بحاجة إلى تمرير معاملات إلى منشئيها. # bad arr = Array.new hash = Hash.new # good arr = [] hash = {} # good because constructor requires parameters x = Hash.new { |h, k| h[k] = {} } يُفضّل استخدام Array#join على Array#* لأسباب تتعلّق بالوضوح. # bad %w(one two three) * ', ' # => 'one, two, three' # good %w(one two three).join(', ') # => 'one, two, three' استخدم الرموز (symbols) بدلا من السلاسل النصية كمفاتيح للـ Hash. # bad hash = { 'one' => 1, 'two' => 2, 'three' => 3 } # good hash = { :one => 1, :two => 2, :three => 3 } على نحو مماثل، استخدم رموز واضحة بدلا من رموز السلاسل النصية عندما يكون ذلك ممكنًا. # bad :"symbol" # good :symbol استخدم Hash#key? بدلا من Hash#has_key? وHash#value? بدلا من Hash#has_value?.فوفقًا لماتز (Matz)، تعتبر الأشكال الأطول مُهملة. # bad hash.has_key?(:test) hash.has_value?(value) # good hash.key?(:test) hash.value?(value) استخدم hash متعدّد الأسطر لأنه يجعل التعليمات البرمجية أكثر قابليّة للقراءة واستخدم الفواصل الزائدة للتأكد من أن تغييرات المعامل لا تتسبب بأسطر diff الغريبة عندما لم يتغيّر المنطق خلاف ذلك. hash = { :protocol => 'https', :only_path => false, :controller => :users, :action => :set_password, :redirect => @redirect_url, :secret => @secret, } استخدم الفاصلة الزائدة في المصفوفة التي تمتد لأكثر من سطر واحد. # good array = [1, 2, 3] # good array = [ "car", "bear", "plane", "zoo", ] السلاسل النصية يُفضّل استخدام استيفاء السلسلة النصية (string interpolation) بدلا من سلّسلة السلسلة النصية: # bad email_with_name = user.name + ' <' + user.email + '>' # good email_with_name = "#{user.name} <#{user.email}>" وعلاوة على ذلك، لا تنسى استيفاء نمط روبي 1.9، لنفترض أنك تُنشئ مفاتيح ذاكرة التخزين المؤقت كالتالي: CACHE_KEY = '_store' cache.write(@user.id + CACHE_KEY) يُفضّل استخدام استيفاء السلسلة النصية (string interpolation) بدلا من سَلسلة السِلسلة النصية: CACHE_KEY = '%d_store' cache.write(CACHE_KEY % @user.id) تجنب استخدام String#+ عندما تحتاج إلى إنشاء قطع بيانات كبيرة، واستخدم بدلا من ذلك String#<<. تحور السَلْسلة مثيل السِلسلة النصية في مكانها وهي أسرع دائما من String#+، والذي ينشئ مجموعة من كائنات السلسلة النصية الجديدة. # good and also fast html = '' html << '<h1>Page title</h1>' paragraphs.each do |paragraph| html << "<p>#{paragraph}</p>" end استخدم \ في نهاية السطر بدلا من + أو << لسَلسلة السلاسل النصية متعددة الأسطر. # bad "Some string is really long and " + "spans multiple lines." "Some string is really long and " << "spans multiple lines." # good "Some string is really long and " \ "spans multiple lines." التعبيرات العادية تجنب استخدام $1-9 لأنه من الصعب متابعة ما يحتويه، واستخدم بدلا منه المجموعات المسماة. # bad /(regexp)/ =~ string ... process $1 # good /(?<meaningful_var>regexp)/ =~ string ... process meaningful_var كن حذرا مع ^ و $ لأنها تطابق بداية/نهاية السطر وليس نهايات السلسلة النصية، فإذا أردت مطابقة كامل السلسلة النصية فاستخدم: \A و\z. string = "some injection\nusername" string[/^username$/] # matches string[/\Ausername\z/] # don't match استخدم المُُعدّل x لتعبيرات (regexps) المعقدة، فهذا سيجعلها أكثر قابلية للقراءة ويمكنك إضافة بعض التعليقات المفيدة، فقط كن حذرا لأنه سيتجاهل الفراغات. regexp = %r{ start # some text \s # white space char (group) # first group (?:alt1|alt2) # some alternation end }x محارف النسبة المئوية يفضل استخدام الأقواس على الأقواس المجعدة، الأقواس المربّعة، أو الأنابيب (pipes) عند استخدم محددات محرف % للتناسق ولأن سلوك محارف % أقرب إلى استدعاء الأسلوب منه إلى البدائل. # bad %w[date locale] %w{date locale} %w|date locale| # good %w(date locale) استخدم %w بحريّة. STATES = %w(draft open closed) استخدم %() للسلاسل النصية المتكونة من سطر واحد والتي تتطلّب الاستيفاء (interpolation) وعلامات الاقتباس المزدوجة المضمّنة ، وبالنسبة للسلاسل النصية المتكونة من عدة أسطر، يُفضل استخدام heredocs. # bad - no interpolation needed %(<div class="text">Some text</div>) # should be '<div class="text">Some text</div>' # bad - no double-quotes %(This is #{quality} style) # should be "This is #{quality} style" # bad - multiple lines %(<div>\n<span class="big">#{exclamation}</span>\n</div>) # should be a heredoc. # good - requires interpolation, has quotes, single line %(<tr><td class="name">#{name}</td>) استخدم ٪ r فقط للتعبيرات العادية التي تتطابق مع أكثر من حرف /. # bad %r(\s+) # still bad %r(^/(.*)$) # should be /^\/(.*)$/ # good %r(^/blog/2011/(.*)$) تجنب استخدام %x إلا إذا أردت استدعاء أمر مع علامة الاقتباس الخلفية (`) - وهو أمر مستبعد إلى حد ما -. # bad date = %x(date) # good date = `date` echo = %x(echo `date`) ريلز عند الرجوع فورا بعد استدعاء render أو redirect_to، ضع return في السطر التالي وليس في نفس السطر. # bad render :text => 'Howdy' and return # good render :text => 'Howdy' return # still bad render :text => 'Howdy' and return if foo.present? # good if foo.present? render :text => 'Howdy' return end نطاقات عند تعريف نطاقات نموذج ActiveRecord، لِفْ العلاقة بـ lambda، وخلافًا لذلك ستفرض العلاقة اتصال قاعدة بيانات في وقت تحميل الصنف (مثيل بدء التشغيل). # bad scope :foo, where(:bar => 1) # good scope :foo, -> { where(:bar => 1) } كن منسجمًا إذا كنت تعدل شيفرة برمجية، فخذ بضعة دقائق لإلقاء نظرة على الشيفرة البرمجية الموجودة وحدد أسلوبها، فإذا كانوا يستخدمون مساحات فارغة حول جميع عواملها الرياضية، فقم بذلك أيضا، وإذا كانت تمتلك التعليقات صناديق صغيرة من علامات hash حولها، فاجعل تعليقاتك كذلك أيضا. الهدف من امتلاك مبادئ توجيهية للنمط هي الحصول على مفردات مشتركة من الشيفرات البرمجية حتى يتمكن الناس من فهم الذي تريد قوله بدلا من كيف تقوله، ونحن نعرض هنا قواعد النمط العالمية حتى يعرف الناس المفردات، لكن النمط المحلي مهم أيضا، فإذا كانت الشيفرة البرمجية التي تضيفها تختلف بشكل كبيرا عن الشيفرات البرمجية التي حولها فستجعل قراءة الشيفرة البرمجية صعبة لذلك تجنب ذلك. ترجمة لدليل Ruby Style Guide من Airbnb على GitHub
  9. تعرفنا في الدرس السابق على أهم الخدع، النصائح والتحذيرات وسنتابع في هذا الدرس مرجع الارتباط المفصّل. 4 مرجع الارتباط المفصّل ستجد في الأقسام التالية تفاصيل حول كل نوع من أنواع الارتباط، بما في ذلك الأساليب التي تضيفها والخيارات التي يمكنك استخدامها عند إعلان الارتباط. 4.1 مرجع ارتباط belongs_to ينشئ ارتباط belongs_to تطابق واحد لواحد (one-to-one) مع نموذج آخر، بمصطلحات قاعد البيانات، يعني هذا الارتباط أن هذا الصنف يحتوي على مفتاح خارجي، إذا كان الصنف الآخر يحتوي على مفتاح خارجي، فيجب عليك في هذه الحالة استخدام has_one بدلًا من ذلك. 4.1.1 أساليب مضافة بواسطة belongs_to عند إعلان ارتباط belongs_to، فسيحصل الصنف المعلن على 5 أساليب مرتبطة بالارتباط: association association=(associate) ({} = build_association(attributes ({} = create_association(attributes ({} = create_association!(attributes reload_association في جميع هذه النماذج، سيُستبدل الارتباط مع symbol الذي مُرر كمعامل أول إلى belongs_to، فعلى سبيل المثال، هذا الإعلان: class Book < ApplicationRecord belongs_to :author end سيحصل كل مثيل نموذج Book على هذه الأساليب: author author= build_author create_author create_author! reload_author 4.1.1.1 association يرجع أسلوب association الكائن المقترن إذا وجد، وإلا فسيُرجع nil. @author = @book.author إذا أُسترد الكائن من قاعدة البيانات لهذا الكائن، ستُرجع النسخة المخبئة، ولتجاوز هذا السلوك (وإجبار القراءة من قاعدة البيانات)، استدعي reload_association# في كائن الأب. @author = @book.reload_author 4.1.1.2 (association=(associate يعيّن أسلوب association= كائن مرتبط لهذا الكائن، في ما وراء الكواليس، يعني هذا استخراج المفتاح الأساسي من الكائن المرتبط وتعيين قيمة المفتاح الخارجي للكائن لنفس قيمته. @book.author = @author 4.1.1.3 ({} = build_association(attributes يُرجع أسلوب build_association كائن جديد لنوع المرتبط، هذا الكائن سيُنشئ من السمات المُمرّرة وسيُعين الارتباط من خلال المفتاح الخارجي لكن لن بعد يحفظ بعد الكائن المرتبط. @author = @book.build_author(author_number: 123, author_name: "John Doe") 4.1.1.4 ({} = create_association(attributes سيرجع أسلوب create_association كائن جديد لنوع المرتبط، هذا الكائن سيُنشئ من السمات المُمررة وسيُعين الارتباط من خلال المفتاح الخارجي، وبمجرد تمرير جميع عمليات التحقيق validations المحددة على النموذج المرتبط، سيُحفظ الكائن المرتبط. @author = @book.create_author(author_number: 123, author_name: "John Doe") 4.1.1.5 ({} = create_association!(attributes يعمل كما create_association في الأعلى، لكنه يُصدر ActiveRecord::RecordInvalid إذا كان السجل record غير صالح. 4.1.2 خيارات لـ belongs_to في حين يستخدم Rails افتراضات ذكية ستعمل بشكل صحيح في أغلب الأحيان، ستحتاج في بعض الأحيان إلى تخصيص مرجع سلوك ارتباط belongs_to، ويمكن تحقيق هذه التخصيصات بسهولة عن طريق تمرير الخيارات وكتل النطاق (scope) عند إنشاء الارتباط، فعلى سبيل المثال، هذا الارتباط يستخدم هذين الخيارين: class Book < ApplicationRecord belongs_to :author, dependent: :destroy, counter_cache: true end يدعم ارتباط belongs_to هذه الخيارات: autosave: class_name: counter_cache: dependent: foreign_key: primary_key: inverse_of: polymorphic: touch: validate: optional: 4.1.2.1 autosave: إذا عيّنت خيار autosave: إلى true، فسيحفظ Rails جميع أعضاء المحمّلين وسيدمر الأعضاء الذين وضع عليهم علامة التدمير كلما حفظت كائن الأب. 4.1.2.2 class_name: إذا لم يكن بالإمكان اشتقاق اسم النموذج الآخر من اسم الارتباط، يمكنك استخدام خيار class_name: لتوفير اسم النموذج، فعلى سبيل المثال، إذا كان الكتاب ينتمي إلى المؤلف، لكن اسم فعلي للنموذج الذي يحتوي على المؤلفين هو Patron: class Book < ApplicationRecord belongs_to :author, class_name: "Patron" end 4.1.2.3 counter_cache: يمكنك استخدام خيار counter_cache: لتجعل عملية العثور على عدد الكائنات التابعة أكثر كفاءة، على سبيل المثال هذه النماذج: class Book < ApplicationRecord belongs_to :author end class Author < ApplicationRecord has_many :books end مع هذه الإعلانات، يتطلب طلب قيمة author.books.size@ الاتصال بقاعدة البيانات لتنفيذ استعلام (*)COUNT، ولنتجنب هذا الاتصال، يمكنك إضافة ذاكرة مؤقتة لتخزين العدد إلى نموذج الانتماء: class Book < ApplicationRecord belongs_to :author, counter_cache: true end class Author < ApplicationRecord has_many :books end مع هذا الإعلان، سيُبقي Rails قيمة الذاكرة المؤقتة مُحدّثة، وسيجيب بتلك القيمة عند الطلب من أسلوب size. على الرغم من تحديد خيار counter_cache: في النموذج الذي يتضمن إعلان belongs_to، يجب إضافة العمود الحالي إلى النموذج المرتبط (has_many)، في الحالة أعلاه، ستحتاج إلى إضافة عمود باسم books_count إلى نموذج Author. يمكنك تجاوز اسم الافتراضي للعمود من خلال تحديد اسم العمود المخصص في إعلان counter_cache بدلا من true، فعلى سبيل المثال، لاستخدام count_of_books بدلا من books_count: class Book < ApplicationRecord belongs_to :author, counter_cache: :count_of_books end class Author < ApplicationRecord has_many :books end 4.1.2.4 :dependent إذا قمت بتعيين خيار dependent: إلى: destroy:، عند تدمير الكائن، ستُستدعى destroy على الكائنات المرتبطة. delete:، عند تدمير الكائن، ستُحذف جميع الكائنات المرتبطة بها مباشرة من قاعدة البيانات دون استدعاء أسلوب destroy. 4.1.2.5 foreign_key: بالاتفاق، يفترض Rails أن العمود المستخدم لحمل المفتاح الخارجي في هذا النموذج هو اسم الارتباط مع إضافة بادئة id_، خيار foreign_key: يُتيح لك تعيين اسم المفتاح الخارجي مباشرة: class Book < ApplicationRecord belongs_to :author, class_name: "Patron", foreign_key: "patron_id" end 4.1.2.6 primary_key: بالاتفاق، يفترض Rails أن عمود id يُستخدم لاحتواء المفتاح الرئيسي للجداول، ويسمح لك خيار primary_key: بتحديد عمود مختلف. على سبيل المثال، إذا كان لدينا جدول users مع guid كمفتاح رئيسي، أردنا جدول todos منفصل لاحتواء المفتاح الخارجي user_id في عمود guid، ثم يمكننا استخدام primary_key لتحقيق ما يشابه هذا: class User < ApplicationRecord self.primary_key = 'guid' # primary key is guid and not id end class Todo < ApplicationRecord belongs_to :user, primary_key: 'guid' end عند تنفيذ user.todos.create@ فستكون قيمة user_id في سجل todo@ كقيمة guid في user@. 4.1.2.7 inverse_of: يحدد خيار inverse_of: اسم عكس هذا الارتباط وهي has_many أو has_one، وهذه لا تعمل في التركيبة مع خيارات polymorphic: class Author < ApplicationRecord has_many :books, inverse_of: :author end class Book < ApplicationRecord belongs_to :author, inverse_of: :books end 4.1.2.8 polymorphic: يشير تمرير true إلى خيار polymorphic: إلى أن الارتباط متعدد الأشكال، وسنتحدث عن الارتباطات متعدد الأشكال لاحقا في هذا الدليل. 4.1.2.9 touch: إذا عيّنت خيار touch: إلى true، فإن timestamp لـ updated_at أو updated_on في كائن المرتبط سيُعيّن إلى الوقت الحالي كلما حُفظ الكائن أو دُمر: class Book < ApplicationRecord belongs_to :author, touch: true end class Author < ApplicationRecord has_many :books end في هذه الحالة، حفظ أو تدمير كتاب سيٌحدّث timestamp في المؤلف المرتبط به، يمكنك أيضًا تحديد سمة timestamp معينة للتحديث: class Book < ApplicationRecord belongs_to :author, touch: :books_updated_at end 4.1.2.10 validate: إذا عيّنت خيار validate: إلى true، فسيتحقق (Validate) الكائنات المرتبطة كلما حفظت هذا الكائن. وهذا الخيار يساوي false بشكل افتراضي، ولن يتحقق الكائنات المرتبطة عند حفظ الكائن. 4.1.2.11 optional: إذا عيّنت خيار optional: إلى true، فلن يتحقق من وجود الكائن المرتبط، وهذا الخيار false بشكل افتراضي. 4.1.3 نطاقات Scopes لـ belongs_to في بعض الأحيان قد تحتاج إلى تخصيص الاستعلام المُستخدم من قبل belongs_to، ويمكن تحقيق هذه التخصيصات عن طريق كتلة scope، فعلى سبيل المثال: class Book < ApplicationRecord belongs_to :author, -> { where active: true }, dependent: :destroy end يمكنك استخدام أي من أساليب الاستعلامات القياسية داخل كتلة scope، وستجد تفاصيل التالية في الأسفل: where includes readonly select 4.1.3.1 where يسمح لك أسلوب where بتحديد شروط كائن المرتبط. class book < ApplicationRecord belongs_to :author, -> { where active: true } end 4.1.3.2 includes يمكنك استخدام أسلوب includes لتحديد الارتباطات من الدرجة الثانية التي تريد تحميلها (eager-loaded) عند استخدام هذا الارتباط، فعلى سبيل المثال، فكر في هذه النماذج: class LineItem < ApplicationRecord belongs_to :book end class Book < ApplicationRecord belongs_to :author has_many :line_items end class Author < ApplicationRecord has_many :books end إذا كنت تسترد المؤلفين مباشرة من سطر العناصر بشكل كثير (line_item.book.author@)، فيمكنك جعل شيفرتك البرمجية أكثر كفاءة من خلال تضمين المؤلفين إلى الارتباط من سطر العناصر إلى الكتب: class LineItem < ApplicationRecord belongs_to :book, -> { includes :author } end class Book < ApplicationRecord belongs_to :author has_many :line_items end class Author < ApplicationRecord has_many :books end 4.1.3.3 readonly سيكون الكائن المرتبط قابل للقراءة فقط عند استرداده عن طريق الارتباط إذا استخدمت readonly. 4.1.3.4 select يسمح لك أسلوب select بتجاوز جملة SELECT (في SQL) والتي تُستخدم لاسترداد البيانات حول الكائن المرتبط، وبشكل افتراضي، سيسترد Rails جميع الأعمدة. 4.1.4 هل توجد أية كائنات مرتبطة؟ يمكنك معرفة هل توجد أية كائنات مرتبطة عن طريقة استخدام أسلوب ?association.nil: if @book.author.nil? @msg = "No author found for this book" end 4.1.5 متى تُحفظ الكائنات؟ إن تعيين كائن إلى ارتباط belongs_to لن يحفظ الكائن بشكل تلقائي، ولن يحفظ كائن المرتبط أيضًا. وسنتابع في الدرس القادم من هذه السلسلة الحديث عن مرجع ارتباط has_one المصدر: توثيقات Ruby on Rails
  10. تعرفنا في الدرس السابق على الارتباطات وأنواعها وسنتابع في هذا الدرس أهم النصائح والخدع والتحذيرات. 3 نصائح، خدع وتحذيرات يجب عليك معرفة هذه الأشياء لتستخدم ارتباطات Active Record بشكل أفضل وأكفأ في تطبيقات Rails: التحكم في التخزين المؤقت. تجنب تضارب الأسماء. تحديث المخطط. التحكم في نطاق (scope) الارتباط. الارتباطات ثنائية الاتجاه. 3.1 التحكم في التخزين المؤقت تبنى جميع الارتباطات حول التخزين المؤقت، والذي يحافظ على نتيجة الاستعلام الأخيرة متاحة للعمليات القادمة، يتم تقاسم ذاكرة التخزين المؤقت عبر الأساليب، على سبيل المثال: author.books # retrieves books from the database author.books.size # uses the cached copy of books author.books.empty? # uses the cached copy of books لكن ماذا لو أردنا إعادة تحميل التخزين المؤقت، لأن البيانات قد تتغير عن طريق أجزاء اخرى من التطبيق؟ فقط أدعو إعادة التحميل في الارتباط: author.books # retrieves books from the database author.books.size # uses the cached copy of books author.books.reload.empty? # discards the cached copy of books # and goes back to the database 3.2 تجنب تضارب الأسماء أنت لا تملك حرية كاملة في اختيار الاسم الذي تريده للارتباطات، لإن إنشاء الارتباط سيضيف أسلوب بهذا الاسم إلى النموذج، ومن السيئ إعطاء اسم ارتباط مستخدم بالفعل لمثيل أسلوب ActiveRecord::Base، فأسلوب الارتباط سيتجاوز أسلوب الأساس وسيكسر الأشياء، من الأسماء السيئة: attributes و connection. 3.3 تحديث المخطط الارتباطات مفيدة للغاية لكنها ليست سحرية، فأنت مسؤول عن المحافظة على مخطط قاعدة البيانات ليطابق الارتباطات، وهذا يعني شيئين في الممارسة العملية حسب نوع الارتباطات التي تصنعها، فارتباطات belongs_to تحتاج إلى إنشاء مفاتيح خارجية، ولارتباطات has_and_belongs_to_many ستحتاج إلى إنشاء جدول الضم المناسب. 3.3.1 إنشاء مفاتيح خارجية لارتباطات belongs_to عندما تعلن عن ارتباط belongs_to، ستحتاج إلى إنشاء مفاتيح خارجية حسب الحاجة، فعلى سبيل المثال، فكر في هذا النموذج: class Book < ApplicationRecord belongs_to :author end يحتاج هذا الإعلان إلى أن يُدعم عن طريق مفتاح خارجي مناسب مُعلن في جدول books: class CreateBooks < ActiveRecord::Migration[5.0] def change create_table :books do |t| t.datetime :published_at t.string :book_number t.integer :author_id end end end إذا أنشئت ارتباط بعد وقت من إنشاء النموذج الأساسي، ستحتاج إلى تذكر إنشاء تهجير add_column لتوفير مفتاح الخارجي الضروري. من الممارسات الجيدة إضافة فهرس (index) إلى المفتاح الخارجي لتحسين أداء الطلبات وإضافة قيد على المفتاح الخارجي لضمان سلامة البيانات المرجعية: class CreateBooks < ActiveRecord::Migration[5.0] def change create_table :books do |t| t.datetime :published_at t.string :book_number t.integer :author_id end add_index :books, :author_id add_foreign_key :books, :authors end end 3.3.2 إنشاء جداول الضم لارتباطات has_and_belongs_to_many إذا أنشئت ارتباط has_and_belongs_to_many، فستحتاج إلى إنشاء جدول الضم (joining table)، إذا لم يحدد اسم جدول الضم بشكل صريح عن طريق خيار join_table:، فسينشئ Active Record الاسم عن طريق استخدام الكتاب المعجمي لأسماء الصنف، فالضم بين نماذج المؤلف والكتاب سيُكوّن اسم جدول الضم بشكل افتراضي هو “authors_books”، لأن A تأتي قبل B في الترتيب المعجمي. مهما كان الاسم، يجب عليك إنشاء جدول الضم يدويا مع التهجير المناسب، فعلى سبيل المثال: class Assembly < ApplicationRecord has_and_belongs_to_many :parts end class Part < ApplicationRecord has_and_belongs_to_many :assemblies end يجب أن تدعم هذه بالتهجير لإنشاء جدول assemblies_parts، والذي يجب أن يُنشئ دون مفتاح رئيسي: class CreateAssembliesPartsJoinTable < ActiveRecord::Migration[5.0] def change create_table :assemblies_parts, id: false do |t| t.integer :assembly_id t.integer :part_id end add_index :assemblies_parts, :assembly_id add_index :assemblies_parts, :part_id end end مررنا id: false إلى create_table لأن الجدول لا يُمثل نموذج، وهذا ضروري للارتباط ليعمل بشكل صحيح. قد تلاحظ تصرفات غريبة في ارتباط has_and_belongs_to_many مثل مُعرّفات نموذج سيئة أو استثناءات حول تضارب المعرّفات، لكنها نادرا ما تحدث. يمكنك استخدام أسلوب create_join_table أيضًا. class CreateAssembliesPartsJoinTable < ActiveRecord::Migration[5.0] def change create_join_table :assemblies, :parts do |t| t.index :assembly_id t.index :part_id end end end 3.4 التحكم في نطاق scope الارتباط تبحث الارتباطات افتراضيا عن الكائنات ضمن نطاق الوحدة (module) الحالية، وهذا جيد عندما تعلن عن نماذج Active Record ضمن الوحدة، فعلى سبيل المثال: module MyApplication module Business class Supplier < ApplicationRecord has_one :account end class Account < ApplicationRecord belongs_to :supplier end end end وهذا سيعمل بشكل صحيح، لأن كل من صنف المُورّد والحساب تم تعريفهما داخل نفس النطاق، لكن الشيفرة البرمجية التالية لن تعمل، لأنه عُرّف المُورّد والحساب في نطاقات مختلفة: module MyApplication module Business class Supplier < ApplicationRecord has_one :account end end module Billing class Account < ApplicationRecord belongs_to :supplier end end end لربط نموذج مع نموذج في مساحة اسم (namespace) مختلفة يجب عليك تحديد اسم الصنف كاملا في إعلان الارتباط: module MyApplication module Business class Supplier < ApplicationRecord has_one :account, class_name: "MyApplication::Billing::Account" end end module Billing class Account < ApplicationRecord belongs_to :supplier, class_name: "MyApplication::Business::Supplier" end end end 3.5 الارتباطات ثنائية الاتجاه من الطبيعي أن تعمل الارتباطات في كلا الاتجاهين، وهذا الأمر يتطلب إعلان في نموذجين مختلفين: class Author < ApplicationRecord has_many :books end class Book < ApplicationRecord belongs_to :author end سيحاول Active Record تلقائيا معرفة أن هذيّن النموذجين يشتركان في ارتباط ثنائي الاتجاه بناءا على اسم الارتباط، وبهذه الطريقة سيحمّل Active Record نسخة واحدة من كائن Author وبذلك سيصبح تطبيقك أكثر كفاءة ويمنع البيانات غير المتناسقة: a = Author.first b = a.books.first a.first_name == b.author.first_name # => true a.first_name = 'David' a.first_name == b.author.first_name # => true يدعم Active Record التعرف التلقائي لأغلب الارتباطات مع الأسماء القياسيّة، ومع ذلك لن يُعرّف Active Record الارتباطات ثنائية الاتجاه تلقائيا إذا احتوت على أي من الخيارات التالية: conditions: through: polymorphic: class_name: foreign_key على سبيل المثال، فكر في إعلان النماذج التالية: class Author < ApplicationRecord has_many :books end class Book < ApplicationRecord belongs_to :writer, class_name: 'Author', foreign_key: 'author_id' end لن يتعرف Active Record تلقائيا على الارتباط ثنائي الاتجاه: a = Author.first b = a.books.first a.first_name == b.writer.first_name # => true a.first_name = 'David' a.first_name == b.writer.first_name # => false يوفر Active Record خيار :inverse_of حتى تتمكن من الإعلان الارتباطات ثنائية الاتجاه بشكل صريح: class Author < ApplicationRecord has_many :books, inverse_of: 'writer' end class Book < ApplicationRecord belongs_to :writer, class_name: 'Author', foreign_key: 'author_id' end من خلال تضمين خيار :inverse_of في إعلان ارتباط has_many، سيتعرّف Active Record على ارتباط ثنائي الاتجاه: a = Author.first b = a.books.first a.first_name == b.writer.first_name # => true a.first_name = 'David' a.first_name == b.writer.first_name # => true توجد بعض القيود على دعم inverse_of: : لا تعمل مع ارتباطات through: لا تعمل مع ارتباطات polymorphic: لا تعمل مع ارتباطات as: وسنتابع في الدرس القادم التعرّف على مرجع الارتباط المفصّل. المصدر: توثيقات Ruby on Rails
  11. سنتعرّف في سلسلة الدروس هذه والتي تبدأ بهذا الدرس على ارتباطات Active Record في روبي أند ريلز وسنبدأ أولًا بمعرفة لماذا الارتباطات: 1 لماذا الارتباطات Associations؟ في Rails، الارتباط association هو اتصال بين نموذجي Active Record. لماذا نحتاج إلى هذه الارتباطات بين النماذج؟ وذلك لأن العمليات المشتركة ستصبح أبسط وأسهل في الشيفرة البرمجية، على سبيل المثال، اعتبر أن تطبيق Rails بسيط يتضمن نموذج للمؤلفين ونموذج للكتب، كل مؤلف قد يملك العديد من الكتب، وبدون الارتباطات، سيشبه إعلان النموذج هذا: class Author < ApplicationRecord end class Book < ApplicationRecord end الآن، لنفترض أننا نريد إضافة كتاب جديد للمؤلف الحالي: @book = Book.create(published_at: Time.now, author_id: @author.id) أو حذف المؤلف مع جميع كتبه: @books = Book.where(author_id: @author.id) @books.each do |book| book.destroy end @author.destroy باستخدام ارتباطات Active Record، يمكننا تبسيط هذه العملية (وغيرها) عن طريق إعلان لـ Rails نخبره بوجود اتصال بين النموذجين، وهذه الشيفرة البرمجية معدلة لإعداد المؤلفين والكتب: class Author < ApplicationRecord has_many :books, dependent: :destroy end class Book < ApplicationRecord belongs_to :author end وبهذا، ستصبح عملية إنشاء كتاب لمؤلف معين أسهل: @book = @author.books.create(published_at: Time.now) بالإضافة إلى أن عملية حذف المؤلف مع جميع كتبه أسهل بكثير: @author.destroy لمزيد من المعلومات حول الأنواع المختلفة للارتباطات، اقرأ القسم التالي من هذا الدليل، وستجد بعدها بعض النصائح والحيل للعمل مع الارتباطات، ومن ثم مرجع كامل للنماذج وخيارات الارتباطات في Rails. 2 أنواع الارتباطات Associations يدعم Rails ستة أنواع من الارتباطات Associations: belongs_to has_one has_many has_many :through has_one :through has_and_belongs_to_many تنفّذ الارتباطات Association باستخدام نداءات نمط ماكرو (macro-style) بحيث يمكنك إضافة ميزات إلى نماذج، فعلى سبيل المثال، من خلال إعلان أن نموذج ينتمي belongs_to إلى آخر، ستجعل Rails يحافظ على بيانات المفتاح الرئيسي والمفتاح الخارجي (Primary Key-Foreign Key) بين مثيلات النموذجين، ويمكنك الحصول على عدد الأساليب المضافة إلى نموذجك. في ما تبقى من هذا الدليل، ستتعلم كيف تُعلن وتستخدم أشكال مختلفة من الارتباطات، لكن أولا، مقدمة قصيرة إلى الحالات التي تتناسب معها كل نوع من الارتباطات. 2.1 ارتباط belongs_to يعيّن ارتباط belongs_to اتصال واحد لواحد (one-to-one) مع نموذج آخر، بحيث أن كل مثيل للنموذج المعلن “يرتبط” بمثيل واحد للنموذج الآخر، فعلى سبيل المثال، إذا كان التطبيق يتضمن مؤلفين وكتب وكل كتاب يرتبط فقط إلى مؤلف واحد، يمكنك إعلان نموذج الكتاب كالتالي: class Book < ApplicationRecord belongs_to :author end عملية التهجير ستشبه هذه: class CreateBooks < ActiveRecord::Migration[5.0] def change create_table :authors do |t| t.string :name t.timestamps end create_table :books do |t| t.belongs_to :author, index: true t.datetime :published_at t.timestamps end end end 2.2 ارتباط has_one يعيّن ارتباط has_one أيضا اتصال واحد لواحد (one-to-one) مع نموذج آخر، لكن مع دلالات (semantics) -وعواقب- مختلفة، فيشير هذا الارتباط أن كل مثيل للنموذج يحتوي أو يمتلك مثيل لنموذج آخر فعلى سبيل المثال، إذا يملك كل مُورّد في تطبيقك حساب واحد فقط، سيشبه إعلان نموذج المورد هذا: class Supplier < ApplicationRecord has_one :account end عملية التهجير ستشبه هذه: class CreateSuppliers < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name t.timestamps end create_table :accounts do |t| t.belongs_to :supplier, index: true t.string :account_number t.timestamps end end end بناءََ على حالة الاستخدام، ستحتاج إلى إنشاء فهرس فريد و/أو إلى قيد مفتاح خارجي (foreign key) على عمود المُورّد لجدول الحسابات، في هذه الحالة، سيشبه تعريف العمود لهذا: create_table :accounts do |t| t.belongs_to :supplier, index: { unique: true }, foreign_key: true # ... end 2.3 ارتباط has_many يشير ارتباط has_many إلى اتصال واحد إلى الكثير (one-to-many) مع نموذج آخر، ستجد في الكثير من الأحيان هذا الارتباط في الجانب الآخر لارتباط belongs_to، وهذا الارتباط يشير إلى أن كل مثيل للنموذج يملك صفر مثيل أو أكثر للنموذج الآخر، فعلى سبيل المثال، في التطبيق الذي يحتوي على المؤلفين وكتب، يمكنك الإعلان عن نموذج المؤلف كالتالي: class Author < ApplicationRecord has_many :books end عملية التهجير ستشبه هذه: class CreateAuthors < ActiveRecord::Migration[5.0] def change create_table :authors do |t| t.string :name t.timestamps end create_table :books do |t| t.belongs_to :author, index: true t.datetime :published_at t.timestamps end end end 2.4 ارتباط has_many :through يُستخدم ارتباط has_many :through لإنشاء اتصال كثير إلى كثير(many-to-many) مع نموذج آخر، فهذا النموذج يشير إلى أن النموذج المُعلن يمكن أن يقابل صفر مثيل أو أكثر من نموذج آخر من خلال نموذج ثالث، فعلى سبيل المثال، فكر في العمل الطبي حيث يحدد المرضى مواعيد لرؤية الأطباء، فسيُعلن الارتباط كالتالي: class Physician < ApplicationRecord has_many :appointments has_many :patients, through: :appointments end class Appointment < ApplicationRecord belongs_to :physician belongs_to :patient end class Patient < ApplicationRecord has_many :appointments has_many :physicians, through: :appointments end عملية التهجير ستشبه هذه: class CreateAppointments < ActiveRecord::Migration[5.0] def change create_table :physicians do |t| t.string :name t.timestamps end create_table :patients do |t| t.string :name t.timestamps end create_table :appointments do |t| t.belongs_to :physician, index: true t.belongs_to :patient, index: true t.datetime :appointment_date t.timestamps end end end يمكنك إدارة مجموعة نماذج المنضمّة عن طريق أساليب ارتباط has_many، فعلى سبيل المثال، إذا عيّنت هذا: physician.patients = patients فإنه سينشئ النماذج المنضمّة تلقائيا للكائنات المرتبطة حديثا، إذا كان بعضها موجود سابقا وفُقِد حاليا، فستُحذف صفوف الضم الخاصة به تلقائيا. يمكنك الاستفادة من ارتباط has_many :through لإنشاء "اختصارات” من خلال ارتباطات has_many متداخلة، فعلى سبيل المثال، إذا كان مستند يملك أقسام عديدة، ويحتوي القسم على فقرات، فقد تحتاج في بعض الأحيان إلى الحصول على مجموعة بسيطة من جميع الفقرات في المستند، ويمكنك إنشاء ذلك عن طريق: class Document < ApplicationRecord has_many :sections has_many :paragraphs, through: :sections end class Section < ApplicationRecord belongs_to :document has_many :paragraphs end class Paragraph < ApplicationRecord belongs_to :section end سيفهم Rails هذا الآن عن طريق محدد through: :sections: @document.paragraphs 2.5 ارتباط has_one :through تنشئ ارتباطات has_one :through اتصال واحد لواحد (one-to-one) مع نموذج آخر، هذا الارتباط يشير إلى أن النموذج المُعلن عنه يمكن أن يقابل مع مثيل من نموذج آخر من خلال نموذج آخر، على سبيل المثال، إذا كان يملك كل مُورّد حساب واحد، وكل حساب مرتبط بسجل حساب واحد، فسيكون نموذج المُورّد كالتالي: class Supplier < ApplicationRecord has_one :account has_one :account_history, through: :account end class Account < ApplicationRecord belongs_to :supplier has_one :account_history end class AccountHistory < ApplicationRecord belongs_to :account end عملية التهجير ستشبه هذه: class CreateAccountHistories < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name t.timestamps end create_table :accounts do |t| t.belongs_to :supplier, index: true t.string :account_number t.timestamps end create_table :account_histories do |t| t.belongs_to :account, index: true t.integer :credit_rating t.timestamps end end end 2.6 الارتباط has_and_belongs_to_many ينشئ ارتباط has_and_belongs_to_many اتصال الكثير إلى الكثير many-to-many مباشر مع نموذج آخر بدون تدخل نموذج ثالث، فعلى سبيل المثال، إذا كان تطبيقك يحتوي على تجميعات وأجزاء، ستجد أجزاء عديدة مع كل تجميع وكل جزء يظهر في الكثير من التجميعات، فيمكنك إعلان هذا النموذج كالتالي: class Assembly < ApplicationRecord has_and_belongs_to_many :parts end class Part < ApplicationRecord has_and_belongs_to_many :assemblies end عملية التهجير ستشبه هذه: class CreateAssembliesAndParts < ActiveRecord::Migration[5.0] def change create_table :assemblies do |t| t.string :name t.timestamps end create_table :parts do |t| t.string :part_number t.timestamps end create_table :assemblies_parts, id: false do |t| t.belongs_to :assembly, index: true t.belongs_to :part, index: true end end end 2.7 الاختيار بين belongs_to و has_one إذا أردت إنشاء علاقة واحد إلى واحد (one-to-one) بين نموذجين، فستحتاج إلى إضافة belongs_to to إلى أحدهم و has_one إلى الآخر، فكيف ستعرف لمن تضيف هذا؟ يمكنك تمييز ذلك عن طريق المكان الذي وضعت فيه المفتاح الخارجي (ستكون في الجدول الصنف الذي أعلنت فيه ارتباط belongs_to)، لكن يجب عليك أن تفكر في معنى الفعلي للبيانات، فعلاقة has_one تعني أنه يوجد شيء خاص بك، أي أن جزء منه يعود لك، فعلى سبيل المثال، من المنطقي القول بأن المُورّد يملك حساب على أن الحساب يملك مُورّد، وهذا يعني أن العلاقة الصحيحة مشابهة لهذه: class Supplier < ApplicationRecord has_one :account end class Account < ApplicationRecord belongs_to :supplier end عملية التهجير ستشبه هذه: class CreateSuppliers < ActiveRecord::Migration[5.0] def change create_table :suppliers do |t| t.string :name t.timestamps end create_table :accounts do |t| t.integer :supplier_id t.string :account_number t.timestamps end add_index :accounts, :supplier_id end end 2.8 الاختيار بين has_many :through و has_and_belongs_to_many يوفر Rails طريقتين لإعلان علاقة الكثير إلى الكثير (many-to-many) بين النماذج، أبسط طريقة هي عن طريق استخدام has_and_belongs_to_many، والتي تمكنك من إنشاء هذا الارتباط مباشرة: class Assembly < ApplicationRecord has_and_belongs_to_many :parts end class Part < ApplicationRecord has_and_belongs_to_many :assemblies end الطريقة الثانية هي عن طريق استخدام has_many :through لجعل الارتباط غير مباشرة، عن طريق ضم نموذج: class Assembly < ApplicationRecord has_many :manifests has_many :parts, through: :manifests end class Manifest < ApplicationRecord belongs_to :assembly belongs_to :part end class Part < ApplicationRecord has_many :manifests has_many :assemblies, through: :manifests end ببساطة، إذا أردت العمل مع نموذج العلاقة ككيان مستقل، يجب عليك إنشاء علاقة has_many :through، وإذا لم تحتاج إلى القيام بأي شيء مع نموذج العلاقة، سيكون من الأسهل إنشاء علاقة has_and_belongs_to_many (لا تنسى إنشاء جدول الضم joining table في قاعدة البيانات). يجب عليك استخدام has_many :through إذا احتجت إلى عمليات تحقق validations، دوال استدعاء callbacks أو سمات attributes إضافيَة في نموذج الضم. 2.9 ارتباطات متعددة الأشكال Polymorphic Associations من المواضيع المتقدمة قليلا في الارتباطات، هي الارتباطات متعددة الأشكال، فعن طريقها، يمكن للنموذج أن يرتبط بأكثر من نموذج بارتباط واحد، فعلى سبيل المثال، قد تملك نموذج صورة التي تنتمي إلى نموذج الموظف أو إلى نموذج المنتج، ويمكنك الإعلان عن ذلك عن طريق التالي: class Picture < ApplicationRecord belongs_to :imageable, polymorphic: true end class Employee < ApplicationRecord has_many :pictures, as: :imageable end class Product < ApplicationRecord has_many :pictures, as: :imageable end فكر في إعلان belongs_to متعدد الأشكال على أنه إنشاء لواجهة يمكن لأي نموذج آخر أن يستخدمها، من مثيل نموذج Employee، يمكنك استرداد مجموع من الصور عن طريق: @employee.pictures. وبنفس الطريقة يمكنك استرداد product.pictures@. إذا كنت تملك مثيل من نموذج الصورة، فيمكنك الحصول على الأب (parent) عن طريق picture.imageable@، ولتحقيق ذلك، تحتاج إلى إعلان كل من عمود مفتاح خارجي وعمود النوع في النموذج الذي أعلنت فيه واجهة متعددة الأشكال: class CreatePictures < ActiveRecord::Migration[5.0] def change create_table :pictures do |t| t.string :name t.integer :imageable_id t.string :imageable_type t.timestamps end add_index :pictures, [:imageable_type, :imageable_id] end end يمكن تبسيط عملية التهجير عن طريق استخدام t.references: class CreatePictures < ActiveRecord::Migration[5.0] def change create_table :pictures do |t| t.string :name t.references :imageable, polymorphic: true, index: true t.timestamps end end end 2.10 ضم ذاتي Self Joins عند تصميم نموذج بيانات، ستجد في بعض الأحيان أن العلاقة يجب أن تكون مرتبطة بنفسها، فعلى سبيل المثال، قد تريد تخزين جميع الموظفين في نموذج قاعدة بيانات واحدة، لكن يجب تقدر أيضا على تتبع العلاقات مثل علاقة المدير بالمرؤوسين، وهذه الحالة يمكن إنشاءها عن طريق ارتباطات الضم الذاتي: class Employee < ApplicationRecord has_many :subordinates, class_name: "Employee", foreign_key: "manager_id" belongs_to :manager, class_name: "Employee" end مع هذا الإعداد، يمكنك استرداد employee.subordinates@ و employee.manager@. في عمليات التهجير/المخطط، ستحتاج إلى إضافة عمود المرجع إلى نفس النموذج. class CreateEmployees < ActiveRecord::Migration[5.0] def change create_table :employees do |t| t.references :manager, index: true t.timestamps end end end وسنتابع التعرّف على الإرتباطات في Active Record في الدروس اللاحقة. المصدر: توثيقات Ruby on Rails
  12. ستتعرّف في هذا الدرس على دورة حياة كائنات Active Record، وستتعلم: دورة حياة كائنات Active Record. كيف تنشئ أساليب دوال الاستدعاء (callback methods) التي تستجيب إلى أحداث في دورة حياة الكائن. كيف تنشئ أصناف خاصة التي تجمع السلوك المشترك لدوال الاستدعاء (callbacks). 1- دورة حياة الكائن يمكن إنشاء، تحديث وتدمير الكائنات أثناء عمل تطبيق Rails، ويوفر Active Record طُرق تُمكنك من التحكم بالتطبيق وبياناته في دورة حياة الكائن . يسمح لك دوال الاستدعاء بإطلاق منطقي (trigger logic) قبل أو بعد تغيير حالة الكائن. 2- نظرة عامة على دوال الاستدعاء callbacks دوال الاستدعاء (callbacks) هي أساليب تُستدعى في لحظات معينة من دورة حياة الكائن وتمكنك من كتابة شيفرة برمجية تعمل عند إنشاء، حفظ، تحديث، حذف، تحقق من صحة أو تحميل كائن Active Record من قاعدة البيانات. 2-1 تسجيل دوال الاستدعاء تحتاج إلى تسجيل دوال الاستدعاء المتوفر حتى تتمكن من استخدامه، فيمكنك وضع دوال الاستدعاء كأساليب عادية، واستخدام أسلوب صنف نمط ماكرو (macro-style) لتسجيلهم كدوال استدعاء: class User < ApplicationRecord validates :login, :email, presence: true before_validation :ensure_login_has_a_value private def ensure_login_has_a_value if login.nil? self.login = email unless email.blank? end end end يمكن لأساليب صنف نمط ماكرو (macro-style) تلقي كتلة (block) لذلك استخدم هذا النمط إذا كانت الشيفرة البرمجية داخل الكتلة قصيرة بحيث يمكن وضعها في سطر واحد: class User < ApplicationRecord validates :login, :email, presence: true before_create do self.name = login.capitalize if name.blank? end end يمكنك تسجيل دوال الاستدعاء ليعمل فقط على بعض أحداث دورة حياة الكائن: class User < ApplicationRecord before_validation :normalize_name, on: :create # :on takes an array as well after_validation :set_location, on: [ :create, :update ] private def normalize_name self.name = name.downcase.titleize end def set_location self.location = LocationService.query(self) end end من الممارسات الجيدة أن تعلن أساليب دوال الاستدعاء كخاص، لأنه يمكن استدعاؤه من خارج النموذج (Model) إذا كان عامََا وبهذا تنتهك مبدأ تغليف الكائن (object encapsulation). 3- دوال الاستدعاء المتوفرة هذه قائمة بجميع دوال استدعاء Active Record المتوفر وهو مرتب بنفس ترتيب استدعاءه خلال العمليات: 3-1 إنشاء كائن before_validation after_validation before_save around_save before_create around_create after_create after_save after_commit/after_rollback 3-2 تحديث كائن before_validation after_validation before_save around_save before_update around_update after_update after_save after_commit/after_rollback 3-3 تدمير كائن before_destroy around_destroy after_destroy after_commit/after_rollback 3-4 after_initialize و after_find ستُستدعى دالة الاستدعاء after_initialize عند إنشاء كائن Active Record، إما مباشرة عن طريق new أو عند تحميل السجل record من قاعدة البيانات، ومن المستحسن تجنب الحاجة إلى تجاوز إنشاء أسلوب Active Record مباشرة. ستُستدعى دالة الاستدعاء after_find في كل مرة يُحمّل فيها Active Record سجل من قاعدة البيانات، وستُستدعى after_find قبل after_initialize إذا تم تعريفهما. لا يملك دوال الاستدعاء after_initialize وafter_find نظرائهم من نوع before_*، لكن يمكن تسجيلهم كباقي دوال الاستدعاء Active Record. class User < ApplicationRecord after_initialize do |user| puts "You have initialized an object!" end after_find do |user| puts "You have found an object!" end end >> User.new You have initialized an object! => #<User id: nil> >> User.first You have found an object! You have initialized an object! => #<User id: 1> 3-5 after_touch ستُستدعى دالة الاستدعاء after_touch كلما يُلمس (touch) كائن Active Record. class User < ApplicationRecord after_touch do |user| puts "You have touched an object" end end >> u = User.create(name: 'Kuldeep') => #<User id: 1, name: "Kuldeep", created_at: "2013-11-25 12:17:49", updated_at: "2013-11-25 12:17:49"> >> u.touch You have touched an object => true يمكن استخدام هذه الدالة جنبا إلى جنب مع belongs_to: class Employee < ApplicationRecord belongs_to :company, touch: true after_touch do puts 'An Employee was touched' end end class Company < ApplicationRecord has_many :employees after_touch :log_when_employees_or_company_touched private def log_when_employees_or_company_touched puts 'Employee/Company was touched' end end >> @employee = Employee.last => #<Employee id: 1, company_id: 1, created_at: "2013-11-25 17:04:22", updated_at: "2013-11-25 17:05:05"> # triggers @employee.company.touch >> @employee.touch Employee/Company was touched An Employee was touched => true 4- تشغيل دوال الاستدعاء هذه أساليب إطلاق (trigger) دوال الاستدعاء: create create! destroy destroy! destroy_all save save! save(validate: false) toggle! update_attribute update update! Valid? بالإضافة إلى ذلك، تُطلق (trigger) دالة الاستدعاء after_find عن طريق أساليب finder التالية: all first find find_by find_by_* find_by_*! find_by_sql last تعمل دالة الاستدعاء after_initialize في كل مرة ينشئ فيها كائن صنف class جديد. 5- تجاوز دوال الاستدعاء كما هو الحال مع عمليات التحقق (validation)، من الممكن أيضا تخطي دوال الاستدعاء عن طريق الأساليب التالية: decrement decrement_counter delete delete_all increment increment_counter toggle touch update_column update_columns update_all update_counters يجب استخدام هذه الأساليب بحذر، لأنه قد يُحتفظ بقواعد الأعمال (generated) الهامة ومنطق التطبيق في دوال الاستدعاء، وقد يؤدي تجاوزها دون فهم الآثار المحتملة إلى بيانات غير صالحة. 6- وقف التنفيذ عند بدء تسجيل دوال استدعاء جديد لنماذجك، سيكون في قائمة الانتظار للتنفيذ، وستشمل هذه القائمة جميع عمليات تحقق (validations) النموذج الخاص بك، ودوال الاستدعاء المسجلة وعمليات قاعدة البيانات التي ستُنفّذ. تُلف سلسلة (chain) دالة الاستدعاء بشكل كامل في العملية (transaction)، إذا أصدرت أي دالة استدعاء استثناء (exception)، فستتوقف السلسلة التي تعمل و يصدر ROLLBACK، وإذا أردت تعمد إيقاف السلسلة، استخدم: throw :abort 7- دوال استدعاء علائقي يعمل دوال الاستدعاء من خلال علاقات النموذج model، ويمكن تعريفه عن طريقه، لنفترض أن المستخدم لديه مقالات عديدة، ويجب حذف مقالات المستخدم في حالة حذف المستخدم، لنضف دالة استدعاء after_destroy إلى نموذج User لترتبط علائقيا بنموذج Model: class User < ApplicationRecord has_many :articles, dependent: :destroy end class Article < ApplicationRecord after_destroy :log_destroy_action def log_destroy_action puts 'Article destroyed' end end >> user = User.first => #<User id: 1> >> user.articles.create! => #<Article id: 1, user_id: 1> >> user.destroy Article destroyed => #<User id: 1> 8- دوال الاستدعاء المشروط كما هو الحال مع عمليات التحقق Validation، يمكن أيضا جعل أسلوب دالة الاستدعاء مشروط بشرط معين عن طريق استخدام خيارات :if و :unless والتي تأخذ رمز (symbol) أو Proc أو مصفوفة (Array). يمكنك استخدام خيار :if عندما تريد تحديد شروط استدعاء دالة الاستدعاء، وإذا أردت وضع شروط لعدم استدعاء دالة الاستدعاء يمكنك استخدام :unless. 8-1 استخدام :if و :unless مع Symbol يمكنك ربط خيارات :if و :unless مع رمز (Symbol) مطابق لاسم الأسلوب الذي سيُستدعى قبل دالة الاستدعاء. لن تُنفّذ دالة الاستدعاء عند استخدام خيار :if إذا ارجع الأسلوب false، وعند استخدام :unless لن تُنفّذ دالة الاستدعاء إذا أرجع الأسلوب true، وهذا الخيار هو الأكثر شيوعا. من الممكن أيضا باستخدام هذا الشكل من التسجيل تسجيل predicates مختلفة، التي يتم استدعاؤها للتحقق ما إذا كان يجب تنفيذ دالة الاستدعاء. class Order < ApplicationRecord before_save :normalize_card_number, if: :paid_with_card? End 8-2 استخدام :if و :unless مع Proc أخيرا، من الممكن ربط :if و :unless مع كائن Proc، وهذا الخيار هو الأنسب عند كتابة أساليب تحقق (validation) قصيرة، وفي العادة من سطر واحد: class Order < ApplicationRecord before_save :normalize_card_number, if: Proc.new { |order| order.paid_with_card? } end 8-3 شروط متعددة لدوال الاستدعاء عند كتابة دوال استدعاء شرطي، من الممكن المزج بين :if و :unless في نفس إعلان دالة الاستدعاء: class Comment < ApplicationRecord after_create :send_email_to_author, if: :author_wants_emails?, unless: Proc.new { |comment| comment.article.ignore_comments? } end 9- أصناف دالة الاستدعاء في بعض الأحيان، تكون أساليب دالة الاستدعاء التي ستكتبها مفيدة وملائمة لإعادة استخدامها من قبل نماذج أخرى، لذا يوفر Active Record إمكانية إنشاء أصناف تغلف أساليب دالة الاستدعاء، لذا يصبح من السهل إعادة استخدامها. هذا مثال أنشئنا فيه صنف مع دالة استدعاء after_destroy لنموذج PictureFile: class PictureFileCallbacks def after_destroy(picture_file) if File.exist?(picture_file.filepath) File.delete(picture_file.filepath) end end end عند الإعلان داخل صنف -كما في المثال أعلاه-، ستتلقى أساليب دالة الاستدعاء كائن النموذج كعامل، ونستطيع الآن استخدام صنف دالة الاستدعاء في النموذج: class PictureFile < ApplicationRecord after_destroy PictureFileCallbacks.new end لاحظ أننا بحاجة إلى إنشاء كائن PictureFileCallbacks جديد لأننا أعلنا دالة الاستدعاء الخاصة بنا على أنها مثيل أسلوب(instance method) ،وستستفيد من هذا خاصة إذا استخدمت دوال الاستدعاء حالة الكائن المثيل، ومع ذلك، في الكثير من الأحيان، سيكون من المنطقي إعلان دوال الاستدعاء كأساليب الصنف: class PictureFileCallbacks def self.after_destroy(picture_file) if File.exist?(picture_file.filepath) File.delete(picture_file.filepath) end end end لن يكون من الضروري إنشاء كائن PictureFileCallbacks إذا أُعلن عن أسلوب دالة الاستدعاء بهذه الطريقة. class PictureFile < ApplicationRecord after_destroy PictureFileCallbacks end يمكنك إعلان العدد الذي تريده من دوال الاستدعاء داخل أصناف دالة الاستدعاء. 10- عمليات دوال الاستدعاء يوجد دالتي استدعاء إضافيتين تعمل عند الانتهاء من عملية قاعدة البيانات: after_commit و after_rollback، وهما مشابهين لـ after_save إلا أنهم لا يعملون حتى يُنفّذ التغيير في قاعدة البيانات أو يتم التراجع عنه، وهما مفيدان للغاية عندما تحتاج نماذج active record إلى التفاعل مع الأنظمة الخارجية والتي هي ليست جزء من عملية قاعدة البيانات. على سبيل المثال، فكر في المثال السابق حيث احتاج نموذج PictureFile إلى حذف ملف بعد تدمير السجل، إذا أُصدر استثناء بعد استدعاء دالة الاستدعاء after_destroy و أُرجعت العملية، فسيحذف الملف وسيبقى النموذج في حالة غير متناسقة، على سبيل المثال، افترض أن picture_file_2 في الشيفرة البرمجية أدناه غير صحيح و أصدر أسلوب save! خطأََ: PictureFile.transaction do picture_file_1.destroy picture_file_2.save! End يمكننا تجنب هذه المشكلة باستخدام دالة الاستدعاء after_commit: class PictureFile < ApplicationRecord after_commit :delete_picture_file_from_disk, on: :destroy def delete_picture_file_from_disk if File.exist?(filepath) File.delete(filepath) end end end بما أنه من الشائع استخدام after_commit عند الإنشاء والتحديث والحذف، فتوجد أسماء مستعارة aliases لهذه العمليات: after_create_commit after_update_commit after_destroy_commit class PictureFile < ApplicationRecord after_destroy_commit :delete_picture_file_from_disk def delete_picture_file_from_disk if File.exist?(filepath) File.delete(filepath) end end end المصدر: توثيقات Ruby on Rails
  13. مقدمة إن التعوّد على سطر الأوامر هي الخطوة الأولى نحو الاستفادة من قوة منصة خادوم لينكس، وهو شرط أساسي لجميع نشاطات المرتبطة بالخواديم والتي قد تتمنى القيام بها في هذه البيئة. على الرغم من وجود بدائل رسومية للعديد من الأدوات إلا أن تعلم سطر الأوامر مهارة ستسمح لك بالعمل بكفاءة وسرعة ومرونة بطريقة لا يمكنك فعلها مع أغلب الواجهات الرسومية (GUI). يجب علينا أن نبدء من مكان ما، لذلك في هذا المقال سوف نغطي الأساسيات: كيف تتنقل في النظام واكتشاف ما حولنا. متطلبات أساسية هذا المقال بسيط وأساسي، لذلك فهو لا يتطلب الكثير من المعرفة المسبقة، ومع ذلك، ستحتاج إلى تسجيل الدخول إلى خادومك الخاص لتبدأ الاستكشاف. الخيارات التي لديك للقيام بهذا تعتمد على نظام التشغيل الذي تستخدمه في المنزل. عندما تنشئ DigitalOcean droplet جديد، سوف يرسلون رسالة عبر البريد الإلكتروني تحتوي على كلمة السر و عنوان IP خاص للوصول إلى خادومك الجديد، استخدم هذا الرابط لمعرفة كيفية الاتصال بخادوم VPS الخاص بك. ssh root@your_IP وثمة خيار آخر عن طريق استخدام زر “Console Access” في الزاوية العلوية على اليمين من لوحة تحكم DigitalOcean، هذا الأمر سينشئ لك طرفية افتراضية مباشرة في نافذة متصفحك. معرفة موقعك عن طريق pwd في هذه المرحلة، يجب أن تكون قد سجلت دخولك إلى خادوم لينكس الخاص بك، وسوف ترى في الغالب شيئا مشابهًا لهذا: root@your_hostname:~# هذا هو الموجه (prompt) حيث نكتب الأوامر، وليس هذا فقط، بل أنت حاليا في مكان محدد في نظام ملفات الخادوم حيث ستكون دائما في مكان معين في التسلسل الهرمي للملفات وهذا الأمر يؤثر على كيفية عمل الأوامر التي تكتبها. هذا الأمر يشبه قيامك بفتح متصفح الملفات في حاسوبك المحلي، يمكنك الضغط على مختلف المجلدات للانتقال إلى مناطق مختلفة من نظام الملفات، وإذا ذهبت إلى قائمة التعديل (edit menu) في متصفح الملفات، سوف تجد بعض الخيارات التي ستُطبق على العناصر الموجودة في المجلد التي أنت فيه، وسطر الأوامر هو تمثيل نصي لنفس الفكرة. فأين نحن الآن بالضبط في نظام ملفاتنا؟ هنالك دليل واحد موجود في الموجه نفسه، فقبل رمز # أو $ في نهاية الموجه (هذا سيعتمد على المستخدم الذي سجّل دخوله)، سوف ترى رمزًا خاصًا ~ وهذا يعني أنك موجود في مجلد المنزل (home). مجلد المنزل هو المكان الذي يتم تخزين ملفات المستخدم، فالرمز ~ هو اختصار لهذا المجلد. هنالك طريقة أخرى لمعرفة موقعنا في نظام الملفات وهي عن طريق استخدام الأمر pwd وهذا الأمر سيكون أول أمر سنتعلمه. اكتب هذه الحروف على الطرفية واضغط على زر الإدخال (Enter): pwd /root إن /root هو مجلد المنزل للمستخدم للمستخدم الجذر (المدير)، إذا كنت قد سجّلت دخولك باستخدام مستخدم آخر، فسوف ترى شيئًا مشابهًا لهذا: pwd /home/your_username في هذا الدرس، لا يهم المستخدم الذي سجّلت دخولك به، فأي من النتيجتين ظهرت لك فهي مناسبة. النظر حولك باستخدام ls الآن أنت تعرف مكانك وفي أي مجلد أنت، لكن لازلت تجهل ما هي المحتويات الأخرى الموجودة في ذلك المجلد، فكيف تستطيع معرفة ذلك؟ ببساطة يمكننا سؤال الخادوم عن الملفات والمجلدات الموجودة في المجلد الحالي عن طريق استخدام الأمر ls، أكتبه الآن على الموجه: ls بعد كتابة هذا الأمر ستعود (في الغالب) إلى موجه الأوامر ولن تحصل على أية معلومات، فهل فشلت عملية تنفيذ هذا الأمر؟ لا، على العكس فقد نجحت لكنه ببساطة ليس هنالك أية ملفات أو مجلدات في مجلدك الحالي. دعونا ننشئ بعض ملفات التجريبية لنرى كيف يعمل الأمر ls عند وجود ملفات في المجلد، أكتب هذا الأمر لإنشاء بضعة ملفات: touch file{1..5} السطر السابق سينشئ لنا 5 ملفات بأسماء file1 و file2… في مجلدك الحالي. لنُجرب الأمر ls لنرى كيف سيتصرف الآن: ls file1 file2 file3 file4 file5 رائع، تعرّف الآن أمر ls على الملفات الموجودة في مجلد المنزل. أغلب الأوامر لديها سلوكيات افتراضية يتم تنفيذها عند استدعائها كما فعلنا في الأعلى، ومع ذلك، فإن أغلب سلوكيات الأمر يمكن التحكم بها عن طريق تمرير المعاملات الاختيارية إليها، وهذه الأخيرة يشار إليها بأسماء عديدة مثل الخيارات “options” والمعاملات “arguments/parameters” والأعلام “flags”… في بعض الأحيان، هذه المعاملات تُفعّل الوظائف الاختيارية المتاحة من خلال الأمر وفي أحيان آخرى تحدد الكائن الذي يجب على الأمر أن يتجنبه. لنبدأ مع الحالة الأولى. استكشاف خيارات ls تقريبا جميع الأوامر تملك خيار المساعدة، وفي أغلب الأوقات يمكنك الوصول إليه عن طريق إضافة --help أو -h إلى نهاية الأمر، يمكنك الآن تجربة هذا مع أمر ls: ls --help Usage: ls [OPTION]... [FILE]... List information about the FILEs (the current directory by default). Sort entries alphabetically if none of -cftuvSUX nor --sort is specified. Mandatory arguments to long options are mandatory for short options too. -a, --all do not ignore entries starting with . -A, --almost-all do not list implied . and .. --author with -l, print the author of each file -b, --escape print C-style escapes for nongraphic characters --block-size=SIZE scale sizes by SIZE before printing them. E.g., . . . سيعطيك هذا بعض الإرشادات حول الاستخدام الصحيح للأمر بالإضافة إلى لمحة حول الخيارات المتاحة لتغيير السلوك الإفتراضي للأوامر. العمود الأيسر يعطيك الحروف التي يجب كتابتها وتمريرها إلى الأمر لتنفيذ ما يوجد في وصف العمود الأيمن. إن --help التي قمنا بإضافتها هي مثال لخيار يمكننا تمريره. ومن الطرق الأخرى لمعرفة الخيارات المتاحة لأمر معين هي عن طريق التحقق من الدليل “manual”، ويمكنك فعل ذلك عن طريق كتابة man متبوعا بالأمر الذي تريد معرفة خياراته. قم بتجربة هذا الآن: man ls يمكنك التنقل في الصفحة كما تشاء عن طريق مفاتيح الأسهم والخروج عن طريق كتابة q. كما ترى، يمتلك ls بضعة خيارات يمكنك تمريرها إلى الأمر لتغيير سلوكه، دعونا نجرب بعضها. ls -l -rw-r--r-- 1 root root 0 Feb 28 19:45 file1 -rw-r--r-- 1 root root 0 Feb 28 19:45 file2 -rw-r--r-- 1 root root 0 Feb 28 19:45 file3 -rw-r--r-- 1 root root 0 Feb 28 19:45 file4 -rw-r--r-- 1 root root 0 Feb 28 19:45 file5 السطر السابق يعرض لنا نفس الملفات الخمسة السابقة لكنه يعرضها بشكل أطول، وهذا الأمر يعطينا المزيد من المعلومات حول الملفات مثل المالك (“root” الأولى)، والمجموعة المالكة (“root” الثانية)، وحجم الملف (0) بالإضافة إلى تاريخ آخر تعديل وبعض المعلومات الأخرى. لنجرب خيارًا آخر: ls -a . .aptitude .bashrc file2 file4 .profile .ssh .. .bash_history file1 file3 file5 .rnd .viminfo عرض لنا هذا الخيار ملفات لم نرها من قبل، إن المعامل -a مرادف للمعامل –all والذي يعرض لنا جميع الملفات الموجودة في المجلد الحالي بما في ذلك الملفات المخفية. في أنظمة لينكس، جميع الملفات التي يبدأ اسمها بنقطة سيتم إخفائها بشكل افتراضي، وهذه الملفات ليست سرية ويمكن لأي شخص إيجادها وتم الحفاظ عليها بهذه الطريقة لتسهيل عملية إدارة الملفات، وعند تمرير -a فسنأمر ls بعرض هذه الملفات المخفية أيضا. يمكننا تمرير عدة معاملات كذلك، وذلك عن طريق وضعهم معا كالتالي: ls -l -a drwx------ 4 root root 4096 Feb 28 19:45 . drwxr-xr-x 23 root root 4096 May 3 2013 .. drwx------ 2 root root 4096 Feb 28 17:19 .aptitude -rw------- 1 root root 2036 Feb 28 18:20 .bash_history -rw-r--r-- 1 root root 570 Jan 31 2010 .bashrc -rw-r--r-- 1 root root 0 Feb 28 19:45 file1 . . . الأمر السابق سيعمل بدون مشاكل، لكن يمكننا أيضا دمج المعاملات كالتالي: ls -la هذه الطريقة ستعمل بالضبط كالطريقة الأولى وتتطلّب وقت أقل للكتابة. ومن الخيارات الأخرى المفيدة خيار -R والذي سيعرض جميع الملفات والمجلدات (ومحتوياتها)، وبما أن المجلدات الموجودة في مجلد المنزل الخاص بنا مخفية، فسنمرر خيار -a أيضا: ls -Ra .: . .aptitude .bashrc file2 file4 .profile .ssh .. .bash_history file1 file3 file5 .rnd .viminfo ./.aptitude: . .. cache config ./.ssh: . .. authorized_keys الآن عرفنا كيف نغير سلوكيات ls، لنغير الآن “الكائن” الذي يعمل عليه ls. استخدام ls في مجلدات أخرى افتراضيا، سيعرض ls محتويات المجلد الحالي، ومع ذلك يمكنك تمرير اسم أي مجلد تريد أن ترى محتوياته في نهاية الأمر. على سبيل المثال، يمكننا رؤية محتويات مجلد /etc الموجود في جميع أنظمة لينكس بكتابة السطر التالي: ls /etc acpi fstab magic rc.local adduser.conf fstab.d magic.mime rc.local.orig aliases fuse.conf mailcap rcS.d aliases.db gai.conf mailcap.order reportbug.conf alternatives groff mailname resolvconf anacrontab group mail.rc resolv.conf apm group- manpath.config rmt . . . كما ترى فإن هنالك الكثير من الملفات في هذا المجلد. أي مسار لمجلد يبدأ بخط مائل (/) يُعرف على أنه مسار “مطلق” وسبب ذلك أنه يشير إلى أعلى مسار المجلد والذي هو مجلد الجذر. ومن الطرق الأخرى للإشارة إلى مجلد هي عن طريق استخدام المسار “النسبي”، وهذا سوف يبحث عن مجلد نسبي مرتبط بالمجلد الذي تتواجد به أنت الآن، وهذه المجلدات لا تبدأ بخط مائل. لا نملك أية مجلدات غير مخفية في مجلدنا الحالي لذلك سننشئ بعضها بسرعة وسنضيف بعض الملفات داخلها، لا تقلق حول عدم فهمك لهذه الأوامر في الوقت الحالي، فهذه الأوامر لإنشاء ملفات فقط لاستعمالها في الاستكشاف، لذلك أُكتبها كما هي: mkdir dir{1..3} touch dir{1..3}/test{A,B,C} سينشئ لنا هذا بعض المجلدات بداخلها ملفات، يمكننا رؤية هذه المجلدات باستخدام أمر ls عادي: ls dir1 dir2 dir3 file1 file2 file3 file4 file5 حتى نتمكن من رؤية ما بداخل مجلد dir1، يمكننا أن نعطي مسارًا مُطلقًا كما في المثال السابق، بإضافة المجلد الذي نريد رؤيته إلى نهاية قيمة مجلدنا الحالي، وسنتمكن من معرفة مجلدنا الحالي عن طريق الأمر التالي: pwd /root وبعد ذلك أضف المجلد الذي نهتم به إلى النهاية: ls /root/dir1 testA testB testC لم نكن مُجبرين على القيام بذلك، يمكننا ببساطة الإشارة إلى المجلدات الموجودة داخل مجلدنا الحالي بأسمائها فقط، كالتالي: ls dir1 testA testB testC إذا لم نبدأ المسار بخط مائل، فسيبحث نظام التشغيل على المسار المجلد الذي يبدأ بمجلدنا الحالي. التجوال في المكان حتى الآن، تعلمنا كيف نجد موقعنا في نظام الملفات كما أننا تعلمنا كيف نستخدم الأمر ls لمعرفة بعض المعلومات حول الملفات الموجودة في مجلدات معينة. لكن كيف نغيّر مجلد عملنا؟ تغيير مجلد عملنا سيسمح لنا باستخدام مسارات مترابطة من أماكن مختلفة ﻷنه في العادة، سيكون من السهل إدارة الملفات في المجلد الذي يحتويها. يمكننا التنقل حول التسلسل الهرمي للملفات باستخدام الأمر cd، هذا الأمر يغيّر المجلد الحالي إلى أي مجلد آخر. هذا أبسط استخدام لهذا الأمر: cd لا يبدو أن هنالك أية نتيجة، في الحقيقة، لم يحدث أي شيء، فعند تنفيذ الأمر cd بدون معلومات إضافية فسيغير موقعك الحالي إلى مجلد المنزل، وبما أننا في مجلد المنزل فلن يقوم الأمر بأي شيء. الطريقة الأساسية لاستخدام هذا الأمر هي كالتالي: cd /path/to/directory في هذا المثال، يمكنك استبدال /path/to/directory بمسار المجلد الذي تريد الانتقال إليه، فعلى سبيل المثال، إذا أردت الانتقال إلى مجلد الجذر، والذي سيكون مساره مجرد خط مائل / لأنه في أعلى شجرة الملفات، يمكننا كتابة التالي: cd / ملاحظة: المجلد الجذر (الذي أشرنا إليه بخط مائل /) يختلف عن مجلد المنزل للمستخدم الجذر (الموجود في /root)، وهذا الأمر سيربكك في البداية، لكن تذكر فقط أن المجلد الأعلى في شجرة نظام الملفات يدعى بالجذر. ستلاحظ أن موجه الأوامر قد تغير، بالضبط قبل رموز # أو $، فالمجلد قد تغير من ~ (تذكر أن رمز ~ يشير إلى مجلد المنزل للمستخدم) إلى مجلد الجذر لنظام الملفات. يمكننا التأكد من موقعنا عن طريق استخدام الأمر pwd مرة أخرى: pwd / كما يمكننا التحقق من الملفات الموجودة في مجلدنا الجديد: ls bin etc lib media proc sbin sys var boot home lib64 mnt root selinux tmp vmlinuz dev initrd.img lost+found opt run srv usr نجحنا بالتحرك نحو مكان جديد، لنحاول الآن الانتقال إلى مجلد جديد باستخدام المسار النسبي (relative path)، هنالك مجلد يدعى usr داخل مجلدنا الحالي، لننتقل إليه عن طريق كتابة: cd usr كما ترون، يمكننا استخدام المسار النسبي مع cd أيضا، والآن كيف نستطيع العودة إلى مجلد الجذر مرة أخرى؟ يمكننا كتابة نفس الأمر الذي استخدمناه سابقا cd /، لكننا سنجرب شيئًا مُختلفًا. لنجرب الانتقال إلى أعلى الشجرة باستخدام المسارات النسبيّة، فكيف نشير إلى المجلد الذي يحتوي مجلدنا الحالي باستخدام المسارات النسبيّة؟ ببساطة يمكننا الإشارة إلى المجلد الذي يحتوي على مجلدنا الحالي والذي يدعى بمجلد الأب باستخدام نقطتين (..). لنعد بمقدار مستوى واحد إلى الأعلى: cd .. pwd / كما ترى عدنا إلى مجلد الجذر. يمكننا أيضا الإشارة إلى مجلدنا الحالي باستخدام نقطة واحدة: ls . bin etc lib media proc sbin sys var boot home lib64 mnt root selinux tmp vmlinuz dev initrd.img lost+found opt run srv usr ستكون هذه مفيدة جدا في العديد من الحالات والتي لن نتعلمها في هذه المرحلة لكنك ستتمكن من الإشارة إلى مجلدك الحالي بسهولة في مراحل لاحقة. كما قلنا سابقا، إن رمز “~” يشير إلى مجلد المنزل، لنستخدم ذلك كبداية لمسار مجلد “dir1” الموجود داخل مجلد المنزل: cd ~/dir1 pwd /root/dir1 انتقلنا الآن إلى مجلد داخل مجلد المنزل بطريقة سهلة باستخدام رمز “~” التي وضعناها في الجزء الأول من المسار. لكن ماذا لو نسيت القيام بشيء في المجلد السابق وتريد العودة إليه؟ يمككنا العودة إلى مجلدنا السابق بكتابة التالي: cd - pwd / عدنا إلى مجلدنا السابق. لنختم الدرس بالعودة إلى مجلد المنزل، يمكننا فعل ذلك باستخدام ~ كمسار للتبديل أو يمكنك أيضا استخدام الوضع الافتراضي لـ cd للعودة إلى مجلد المنزل إذا لم نضف أي مسار إلى الأمر، لنجرب ذلك: cd pwd /root كما ترى، نجحنا في العودة إلى مجلد المنزل. الخاتمة ستمتلك الآن الأدوات التي تحتاجها لاستكشاف نظام الملفات، فعلى الرغم من أنك لم تكتشف كيف تقرأ الملفات إلا أنك أصبحت قادرا على التجوال وتصفح النظام بسهولة بالإضافة إلى قدرتك على معرفة مكانك والملفات حولك. ترجمة -وبتصرف- للمقال: How To Use cd, pwd, and ls to Explore the File System on a Linux Server لصاحبه Justin Ellingwood
  14. يبدو أن المشكلة ناتجة من اختلاف مفسرات css3 والقيم الافتراضية بين المتصفحات، حاول وضع الشيفرة البرمجية التالية في ملف/جزء css الخاص بصفحتك/موقعك والتي على الأغلب ستحل هذه المشكلة: * { margin: 0; padding: 0; }
  15. لا يمكنك الإعتماد على جافا سكربت الخام في التعامل مع الخادم مثل إدارة قواعد البيانات لذلك تحتاج إلى لغات مثل php لفعل ذلك، لكن في الخوادم الحديثة فإنه يتم استخدام جافاسكربت لكل شيء بما في ذلك التعامل مع الخوادم وذلك عن طريق Node.js و Express.