المحتوى عن 'تطبيقات ويب'.



مزيد من الخيارات

  • ابحث بالكلمات المفتاحية

    أضف وسومًا وافصل بينها بفواصل ","
  • ابحث باسم الكاتب

نوع المُحتوى


التصنيفات

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

التصنيفات

  • PHP
    • Laravel
    • ووردبريس
  • جافاسكريبت
    • Node.js
    • jQuery
    • AngularJS
    • Cordova
  • HTML
    • HTML5
  • CSS
  • SQL
  • سي شارب #C
    • منصة Xamarin
  • بايثون
    • Flask
    • Django
  • لغة روبي
    • Sass
    • إطار عمل Bootstrap
    • إطار العمل Ruby on Rails
  • لغة Go
  • لغة جافا
  • لغة Kotlin
  • برمجة أندرويد
  • لغة Swift
  • لغة R
  • لغة TypeScript
  • ASP.NET
    • ASP.NET Core
  • سير العمل
    • Git
  • صناعة الألعاب
    • Unity3D
  • مقالات برمجة عامة

التصنيفات

  • تجربة المستخدم
  • الرسوميات
    • إنكسكيب
    • أدوبي إليستريتور
    • كوريل درو
  • التصميم الجرافيكي
    • أدوبي فوتوشوب
    • أدوبي إن ديزاين
    • جيمب
  • التصميم ثلاثي الأبعاد
    • 3Ds Max
    • Blender
  • نصائح وإرشادات
  • مقالات تصميم عامة

التصنيفات

  • خواديم
    • الويب HTTP
    • قواعد البيانات
    • البريد الإلكتروني
    • DNS
    • Samba
  • الحوسبة السّحابية
    • Docker
  • إدارة الإعدادات والنّشر
    • Chef
    • Puppet
    • Ansible
  • لينكس
  • FreeBSD
  • حماية
    • الجدران النارية
    • VPN
    • SSH
  • مقالات DevOps عامة

التصنيفات

  • التسويق بالأداء
    • أدوات تحليل الزوار
  • تهيئة محركات البحث SEO
  • الشبكات الاجتماعية
  • التسويق بالبريد الالكتروني
  • التسويق الضمني
  • التسويق بالرسائل النصية القصيرة
  • استسراع النمو
  • المبيعات
  • تجارب ونصائح

التصنيفات

  • إدارة مالية
  • الإنتاجية
  • تجارب
  • مشاريع جانبية
  • التعامل مع العملاء
  • الحفاظ على الصحة
  • التسويق الذاتي
  • مقالات عمل حر عامة

التصنيفات

  • الإنتاجية وسير العمل
    • مايكروسوفت أوفيس
    • ليبر أوفيس
    • جوجل درايف
    • شيربوينت
    • Evernote
    • Trello
  • تطبيقات الويب
    • ووردبريس
    • ماجنتو
  • أندرويد
  • iOS
  • macOS
  • ويندوز

التصنيفات

  • شهادات سيسكو
    • CCNA
  • شهادات مايكروسوفت
  • شهادات Amazon Web Services
  • شهادات ريدهات
    • RHCSA
  • شهادات CompTIA
  • مقالات عامة

أسئلة وأجوبة

  • الأقسام
    • أسئلة ريادة الأعمال
    • أسئلة العمل الحر
    • أسئلة التسويق والمبيعات
    • أسئلة البرمجة
    • أسئلة التصميم
    • أسئلة DevOps
    • أسئلة البرامج والتطبيقات
    • أسئلة الشهادات المتخصصة

التصنيفات

  • ريادة الأعمال
  • العمل الحر
  • التسويق والمبيعات
  • البرمجة
  • التصميم
  • DevOps

تمّ العثور على 7 نتائج

  1. هذا هو الجزء الأخير من سلسلة “مدخل إلى إطار العمل Ruby on Rails” وفي هذا الجزء سنعيد هيكلة الشيفرة التي كتبناها في الأجزاء السابقة من السلسلة، وسنتعرّف إلى نظام الاستيثاق البسيط الذي يقدّمه إطار العمل Rails. إعادة هيكلة الشيفرة بعد أن أصبحت المقالات والتعليقات تعمل بصورة جيدة، لنلقِ نظرة على القالب app/views/articles/show.html.erb . يبدو الملف طويلًا جدًّا، لذا سنستخدم الملفات الجزئية لتنظيف وترتيب الشيفرة البرمجية. تصيير مجموعة الملفات الجزئية في البداية سننشئ ملفًّا جزئيًا خاصًّا بالتعليقات وظيفته عرض جميع التعليقات الخاصّة بالمقالة. أنشئ الملف app/views/comments/_comment.html.erb وأضف إليه الشيفرة التالية: <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> والآن يمكنك تعديل الملف `app/views/articles/show.html.erb` كما يلي: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> بهذه الطريقة سيتم تصيير الملف الجزئي في app/views/comments/_comment.html.erb لكلّ تعليق موجود في مجموعة @article.comments، وعندما يتنقّل التابع render بين عناصر مجموعة التعليقات فإنه يُسند كل تعليق إلى متغيّر محلي local variable يحمل اسم الملف الجزئي ذاته، وفي حالتنا هذه comment والذي يكون متوفّرًا في الملف الجزئي. تصيير الملف الجزئي الخاصّ بالاستمارة لنقم بإزالة قسم التعليقات الجديد إلى ملف جزئي خاصّ به، ومرة أخرى أنشئ ملفًّا باسم _form.html.erb في المجلد app/views/comments/ وأضف إليه ما يلي: <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> ثم عدّل الملف app/views/articles/show.html.erb ليصبح بالصورة التالية: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <%= render @article.comments %> <h2>Add a comment:</h2> <%= render 'comments/form' %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> يعرّف تابع render الثاني القالب الجزئي الذي نرغب في تصييره وهو comments/form، ونظرًا لوجود المحرّف / ضمن هذه السلسلة النصّية سيعرف Rails بأنّك ترغب في تصيير الملف _form.html.erb الموجود في المجلد app/views/comments. أما الكائن @article فسيكون متوفّرًا لأيّ ملفّ جزئي يتم تصييره في العرض لأنّنا عرّفناه كمتغيّر من نوع instance. حذف التعليقات إن القدرة على حذف التعليقات المزعجة هي من الميزات المطلوب توفرها في المدوّنة، ولتنفيذ ذلك سنحتاج إلى إضافة رابط لحذف التعليقات ضمن العرض وإلى حدث destroy في المتحكّم CommentsController. لذا سنضيف أوّلًا رابط الحذف ضمن الملفّ الجزئي app/views/comments/_comment.html.erb وكما يلي: <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <p> <%= link_to 'Destroy Comment', [comment.article, comment], method: :delete, data: { confirm: 'Are you sure?' } %> </p> سيؤدّي النقر على هذا الرابط إلى إرسال الفعل DELETE متمثّلًا بالرابط /articles/:article_id/comments/:id إلى المتحكّم CommentsController، والذي سيبحث بدوره - مستعينًا بهذا الرابط - عن التعليق المراد حذفه من قاعدة البيانات. لنضِف حدث destroy إلى المتحكّم في الملف app/controllers/comments_controller.rb: class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end def destroy @article = Article.find(params[:article_id]) @comment = @article.comments.find(params[:id]) @comment.destroy redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end سيبحث الحدث destroy عن التعليق المراد حذفه، ثم يعيّن موقعه في مجموعة @article.comments ثم يحذفه من قاعدة البيانات ويعيد توجيهنا إلى حدث show الخاصّ بالمقالة. حذف الكائنات المترابطة من البديهي أنّه عند حذف مقالة معيّنة فإن من الواجب أن يتم حذف التعليقات المرتبطة بها، وإلا فستشغل هذه التعليقات مساحة ضمن قاعدة البيانات دون أيّ فائدة. يتيح لنا Rails استخدام الخيار dependent لتحقيق ذلك. توجّه إلى نموذج Article (app/models/article.rb) وعدّله بالصورة التالية: class Article < ApplicationRecord has_many :comments, dependent: :destroy validates :title, presence: true, length: { minimum: 5 } end الاستيثاق Authentication في Rails إن كنت ترغب في نشر المدوّنة على الإنترنت، سيكون بإمكان أي شخص إضافة وتعديل وحذف المقالات والتعليقات فيها. يقدّم Rails نظام استيثاق HTTP بسيط يمكن استخدامه في التطبيقات البسيطة كتطبيقنا هذا. سنحتاج في المتحكّم ArticlesController إلى وسيلة لمنع وصول الشخص غير المستوثق منه إلى الأحداث التي يتضمّنها هذا المتحكّم، ويمكن استخدام تابع http_basic_authenticate_with لتحقيق ذلك. ولاستخدام نظام الاستثياق سنقوم بالإفصاح عنه في بداية ملف المتحكّم ArticlesController in app/controllers/articles_controller.rb وسنستوثق من جميع الأحداث المتوفّرة في هذا المتحكّم عدا حدثي index وshow: class ArticlesController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", except: [:index, :show] def index @articles = Article.all end # بقيّة الشيفرة ... كذلك سنسمح للمستخدمين المستوثق منهم فقط بحذف التعليقات، لذا أضف الشيفرة التالية إلى المتحكّم CommentsController في الملف app/controllers/comments_controller.rb: class CommentsController < ApplicationController http_basic_authenticate_with name: "dhh", password: "secret", only: :destroy def create @article = Article.find(params[:article_id]) # ... end # بقيّة الشيفرة ... والآن إن حاولت إنشاء مقالة جديدة، ستتلقّى طلب استيثاق كهذا: جدير بالذكر أنّ هناك العديد من وسائل الاستيثاق في تطبيقات Rails، أشهرها Devise rails engine و Authlogic. إطار العمل Rails ونظام الترميز UTF-8 إن أسهل طريقة للعمل مع Rails هي تخزين جميع البيانات الخارجية بنظام الترميز UTF-8، وإن لم تفعل ذلك فغالبًا ما تقوم مكتبات Ruby وإطار العمل Rails بتحويل البيانات الأصلية إلى هذا الترميز، ولكن لا يمكن الاعتماد على هذه المكتبات بصورة تامّة، ويفضّل التأكد من أنّ جميع البيانات الخارجية مرمّزة بهذا النظام. وفي حال حدوث أي خطأ في نظام الترميز فإن الحروف ستظهر في المتصفّح غالبًا على هيئة أشكال معينية سوداء بداخلها علامة استفهام، أو قد تظهر الحروف على هيئة رموز غريبة كأن يظهر الرمز “ü” بدلاً من الحرف “ü”. يتّخذ Rails بعض الإجراءات في نظامه الداخلي للتقليل من المسبّبات الشائعة لهذه المشاكل والتي يمكن الكشف عنها وتصحيحها بصورة تلقائية. ولكن، إن كنت تتعامل مع بيانات من مصادر خارجية غير مخزّنة بترميز UTF-8، لن يكون Rails قادرًا على الكشف بصورة تلقائية عن أسباب المشكلة أو تقديم حلّ لها. وهناك مصدران شائعان للبيانات غير المخزّنة بترميز UTF-8: محرر النصوص: تحفظ معظم محرّرات النصوص الملفات البرمجية بصيغة UTF-8، وإن لم يقم محرّر النصوص الذي تستخدمه في كتابة الشيفرات البرمجية بذلك، فقد ينتج عن ذلك تحوّل الحروف الخاصّة أو حروف اللغات الأخرى غير الإنكليزية إلى التحول في المتصفّح إلى أشكال معينية بداخلها علامة استفهام. ينطبق هذا الأمر كذلك على ملفات الترجمة i18n. تجدر الإشارة إلى أنّه تتيح معظم محررات النصوص التي لا تحفظ الملفات البرمجية بهذا الترميز افتراضيًّا (مثل Dreamweaver) إمكانية تغيير الترميز الافتراضي للملفات المحفوظة إلى نظام UTF-8، وننصح بالقيام بذلك. قاعدة البيانات: يحوّل Rails البيانات القادمة من قاعدة البيانات إلى ترميز UTF-8، ولكن إن لم يكن هذا نظام الترميز هذا مستخدمًا من طرف قاعدة البيانات فلن يكون بالإمكان تخزين جميع المحارف المدخلة من قبل المستخدم. فعلى سبيل المثال، إن كان نظام الترميز الداخلي لقاعدة البيانات هو Latin-1 وأدخل المستخدم كلمات باللغة الروسية أو العربية أو اليابانية، فستخسر البيانات إلى الأبد بمجرد دخولها إلى قاعدة البيانات. لذا ينصح دائمًا بتحويل نظام الترميز الداخلي في قاعدة البيانات إلى نظام UTF-8. المصدر: توثيقات Ruby on Rails.
  2. تحدّثنا في الجزء السابق من هذه السلسلة عن النماذج في إطار العمل Ruby on Rails وتعرّفنا على طريقة إنشائها والتعامل معها من خلال كتابة الشيفرة المسؤولة عن حفظ المقالة الجديدة في قاعدة البيانات. في الجزء الثاني من هذا الموضوع سنتعلّم كيفية ربط نموذجين مع بعضهما البعض من خلال إنشاء نموذج جديد خاصّ بالتعليقات. ولكن قبل ذلك سنكمل ما بدأناه في الدروس السابقة من السلسلة في بناء عمليات “CRUD” حيث غطّينا سابقًا عمليتي الإنشاء Create و القراءة Read، وسنغطي اليوم العمليتين المتبقّيتين وهما التحديث Update والحذف Destroy. تحديث المقالات الخطوة الأولى في عملية تحديث المقالات هي إضافة حدث edit إلى المتحكم ArticlesController بين حدثي new و create وكما يلي: def new @article = Article.new end def edit @article = Article.find(params[:id]) end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end سيتضمن العرض استمارة مشابهة لتلك التي استخدمناها في إنشاء المقالات الجديدة. أنشئ ملفًّا باسم app/views/articles/edit.html.erb وأضف إليه الشيفرة التالية: <h1>Edit article</h1> <%= form_for(@article) do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> سنوجّه الاستمارة هذه المرة إلى حدث update والذي لم نقم بتعريفه حتى الآن. يؤدي تمرير كائن المقالة للتابع إلى إنشاء عنوان url لإرسال استمارة المقالة التي تم تعديلها، ومن خلال هذا الخيار نخبر Rails بأنّنا نرغب في أن يتم إرسال هذا النموذج من خلال فعل HTTP PATCH وهو أحد أفعال HTTP التي تستخدم في تحديث الموارد حسب بروتوكول REST. يمكن أن يكون المعامل الأول لـ form_for كائنًا، مثلًا @articl، والذي سيؤدي بالدالة المساعدة إلى ملء الاستمارة بالحقول التابعة للكائن، ويؤدي تمرير الرمز (:article) بنفس اسم المتغيّر من نوع instance (@article) إلى نفس النتيجة تلقائيًا. والآن سنقوم بإنشاء الحدث update في المتحكّم app/controllers/articles_controller.rb وسنضيفه بين حدث create والتابع ذي المحدّد الخاصّ private: def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render 'edit' end end private def article_params params.require(:article).permit(:title, :text) end يستخدم الحدث update عندما ترغب في تحديث سجل موجود في قاعدة البيانات، ويستقبل هذا الحدث جدول تقطيع hash يحتوي الخصائص التي ترغب في تحديثها. وكما سبق، في حال وجود خطأ في عملية التحديث سنعرض الاستمارة على المستخدم من جديد. سنستخدم التابع article_params الذي عرّفناه في وقت سابق للحدث create. لا حاجة لتمرير جميع الخصائص لغرض تحديثها، فعلى سبيل المثال، إن تم استدعاء @article.update(title: 'A new title') فسيقوم Rails بتحديث خاصية العنوان فقط، ويترك باقي الخصائص دون تعديل. أخيرًا، نرغب في عرض رابط إلى الحدث edit في الصفحة التي نعرض فيها قائمة المقالات، لذا توجّه إلى الملف app/views/articles/index.html.erb وأضف الرابط ليظهر إلى جانب رابط “Show”: <table> <tr> <th>Title</th> <th>Text</th> <th colspan="2"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> </tr> <% end %> </table> سنضيف كذلك رابطًا إلى قالب app/views/articles/show.html.erb ليظهر رابط “Edit” في صفحة المقالة أيضًا: ... <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> هذا هو شكل تطبيقنا حتى هذه اللحظة: استخدام الملفات الجزئية partials لإزالة التكرار من العروض تبدو صفحة تحرير المقالة مشابهة تمامًا لصفحة إنشاء مقالة جديدة، وفي الواقع تستخدم الصفحتان الشيفرة ذاتها لعرض الاستمارة. سنقوم الآن بالتخلص من هذا التكرار باستخدام ملفات العرض الجزئية. تحمل هذه الملفات أسماء تبدأ بالمحرف (_). أنشئ ملفًّا جديدًا باسم _form.html.erb ضمن المسار app/views/articles/ وأضف إليه الشيفرة التالية: <%= form_for @article do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> لاحظ أننا لم نغيّر شيئًا باستثناء الإعلان عن التابع form_for وسبب استخدام هذه الأسلوب المختصر والبسيط في الإعلان عن التابع form_for للتعبير عن الاستمارتين هو أن @article عبارة عن مورد يرتبط بمجموعةٍ من مسارات RESTful، وبإمكان Rails أن يخمّن عنوان URI والتابع الذي يجب استخدامه. والآن لنقم بتحديث العرض app/views/articles/new.html.erb لاستخدام الملف الجزئي الذي أنشأناه وسنقوم بإعادة كتابة العرض من جديد وكما يلي: <h1>New article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %> ثم قم بالأمر عينه في ملف العرض app/views/articles/edit.html.erb: <h1>Edit article</h1> <%= render 'form' %> <%= link_to 'Back', articles_path %> حذف المقالات هذه هي العملية الأخيرة ضمن عمليات CRUD، وبحسب معايير REST فإن المسار الذي يؤدي إلى حذف المقالات وكما يظهر في مخرجات الأمر bin/rails routes هو: DELETE /articles/:id(.:format) articles#destroy يجب استخدام الفعل DELETE في المسار المسؤول عن حذف الموارد، أما في حال استخدام الفعل GET فسيكون بالإمكان إنشاء رابط خبيث كهذا الرابط مثلًا: <a href='http://example.com/articles/1/destroy'>look at this cat!</a> سنستخدم التابع delete لحذف المصادر، وهذا المسار مرتبط بالحدث destroy ضمن المتحكّم app/controllers/articles_controller.rb والذي لم نقم بإنشائه بعد. عادة ما يكون التابع destroy التابع الأخير ضمن المتحكّم، وكما هو الحال مع بقية التوابع العامّة public يجب الإعلان عنه قبل أي توابع خاصّة أو محميّة protected. def destroy @article = Article.find(params[:id]) @article.destroy redirect_to articles_path end الصورة النهائية للمتحكّم ArticleController في الملف app/controllers/articles_controller.rb هي: class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new @article = Article.new end def edit @article = Article.find(params[:id]) end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end def update @article = Article.find(params[:id]) if @article.update(article_params) redirect_to @article else render 'edit' end end def destroy @article = Article.find(params[:id]) @article.destroy redirect_to articles_path end private def article_params params.require(:article).permit(:title, :text) end end يمكن استدعاء التابع destroy في كائنات التسجيلة النشطة Active Record عندما ترغب في حذفها من قاعدة البيانات. لاحظ أنّنا لسنا بحاجة لإضافة عرض خاص بهذا الحدث لأنّنا نعيد توجيه المستخدم إلى الحدث index. أخيرًا أضف رابط ‘Destroy’ إلى القالب app/views/articles/index.html.erb لنربط كل الصفحات مع بعضها البعض. <h1>Listing Articles</h1> <%= link_to 'New article', new_article_path %> <table> <tr> <th>Title</th> <th>Text</th> <th colspan="3"></th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> <td><%= link_to 'Edit', edit_article_path(article) %></td> <td><%= link_to 'Destroy', article_path(article), method: :delete, data: { confirm: 'Are you sure?' } %></td> </tr> <% end %> </table> استخدمنا هنا التابع link_to بطريقة مختلفة، حيث مررّنا اسم المسار كمعامل ثانٍ، ثمّ مرّرنا الخيارات الأخرى بعد ذلك. تستخدم الخيارات method: :delete وdata: { confirm: 'Are you sure?' } كخصائص HTML5 بحيث يؤدي الضغط على الرابط إلى عرض مربع حوار للتأكد من رغبة المستخدم في حذف المقالة، ثم إرسال الرابط باستخدام التابع delete. تتمّ تعملية التحقّق هذه بواسطة ملف JavaScript الذي يحمل الاسم rails-ujs والموجود بصورة افتراضية في مخطط التطبيق (app/views/layouts/application.html.erb)، وفي حال عدم وجود هذا الملف لن يظهر مربع الحوار التأكيدي للمستخدم. تهانينا أصبح بإمكانك الآن إنشاء وعرض وسرد وتحديث وحذف المقالات في مدوّنتك. إضافة النموذج الخاصّ بالتعليقات سنقوم الآن بإنشاء نموذج جديد في تطبيقنا هذا ستكون وظيفته التعامل مع التعليقات. إنشاء النموذج لإنشاء النموذج الخاص بالتعليقات سنتبع الأسلوب السابق نفسه وذلك باستخدام أداة المولّد لإنشاء نموذج يحمل الاسم Comment ويمثّل مرجعًا إلى المقالة. اكتب الأمر التالي في سطر الأوامر: $ bin/rails generate model Comment commenter:string body:text article:references سينشئ هذا الأمر أربعة ملفات: الملف Purpose الملف/المجلد الوظيفة db/migrate/20140120201010_create_comments.rb ملف التهجير المسؤول عن إنشاء جدول التعليقات في قاعدة البيانات (سيحمل اسم الملف لديك ختمًا زمنيًا مختلفًا) app/models/comment.rb النموذج الخاص بالتعليقات test/models/comment_test.rb ملف الاختبارات الخاص بنموذج التعليقات test/fixtures/comments.yml نماذج تعليقات تستخدم في إجراء الاختبارات لنلق نظرة في البداية على ملف app/models/comment.rb: class Comment < ApplicationRecord belongs_to :article end كما تلاحظ فمحتوى هذا الملف مشابه لنموذج Article الذي أنشأناه سابقًا، والفارق الوحيد هو السطر belongs_to :article والذي ينشئ رابطًا بين النموذجين، وسنتحدّث عن الروابط بعد قليل. أما الكلمة المفتاحية (:references) ضمن الأمر الذي قمنا بتنفيذه في سطر الأوامر، فهي نوع خاص من البيانات بالنسبة للنماذج. تنشئ هذه الكلمة المفتاحية عمودًا في الجدول الموجود في قاعدة البيانات يحمل اسم النموذج الذي تمّ تمريره إلى هذه الكلمة مع إضافة _id والذي يمثّل عددًا صحيحًا. ستتضح الأمور أكثر بالنسبة إليك إن تفحّصت ملف db/schema.rb أدناه. قام Rails - بالإضافة إلى إنشاء النموذج - بإنشاء تهجير وظيفته إنشاء الجدول المقابل للنموذج في قاعدة البيانات: class CreateComments < ActiveRecord::Migration[5.0] def change create_table :comments do |t| t.string :commenter t.text :body t.references :article, foreign_key: true t.timestamps end end end يُنشئ السطر t.references عمودًا من نوع integer باسم article_id إضافة إلى فهرس index خاص بهذا العمود وقيد مفتاح خارجي Foreign Key Constraint والذي يشير إلى عمود id في جدول المقالات. والآن نفذ التهجير باستخدام الأمر التالي: $ bin/rails db:migrate ينفّذ Rails التهجيرات غير المنفّذة فقط؛ لذا ستكون نتيجة الأمر التالي كما يلي: == CreateComments: migrating ================================================= -- create_table(:comments) -> 0.0115s == CreateComments: migrated (0.0119s) ======================================== ربط النماذج مع بعضها البعض تسهّل روابط التسجيلة النشطة تكوين العلاقات بين النماذج، وفي حالتنا هذه سنُنشئ علاقة بين جدولي التعليقات والمقالات، ولو فكّرنا في طبيعة العلاقة التي تربط بينهما فسنجد أنه: ينتمي كل تعليق إلى مقالة واحدة. تمتلك المقالة الواحدة العديد من التعليقات. يستخدم Rails صياغة مشابهة للربط بين النماذج، وقد شاهدنا في نموذج Comment في الملف app/models/comment.rb الشيفرة المسؤولة عن ربط كل تعليق بمقالة واحدة: class Comment < ApplicationRecord belongs_to :article end سنحتاج الآن إلى تكوين الجانب الثاني من الرابطة، أي ربط المقالات بالتعليقات، لذا توجّه إلى الملف app/models/article.rb وعدّله بالصورة التالية: class Article < ApplicationRecord has_many :comments validates :title, presence: true, length: { minimum: 5 } end والآن أصبح النموذجان مرتبطين مع بعضهما البعض تلقائيًا، فعلى سبيل المثال، في حال كان لدينا متغيّر @article والذي يمثّل مقالة معيّنة، يمكن استدعاء جميع التعليقات المرتبطة بتلك المقالة على هيئة مصفوفة وذلك من خلال @article.comments. إضافة مسار خاص بالتعليقات كما هو الحال مع متحكم welcome سنحتاج إلى إضافة مسار نحدّد من خلاله العنوان الذي نرغب في استخدامه لمشاهدة التعليقات؛ لذا افتح ملف config/routes.rb مرة أخرى، وعدّله كما يلي: resources :articles do resources :comments end بهذه الطريقة تصبح التعليقات بمثابة موارد مضمّنة في المقالات، وهذه الطريقة هي جزء من العلاقة الهرمية التي تنشأ بين المقالات والتعليقات. إنشاء المتحكّم الخاصّ بالتعليقات بعد أن انتهينا من إعداد النموذج، أصبح بإمكاننا الآن إنشاء المتحكّم الخاص بالتعليقات، وسنستخدم أداة المولّد كما فعلنا سابقًا: $ bin/rails generate controller Comments سينشئ هذا الأمر خمسة ملفات إضافة إلى مجلّد فارغ: الملف/المجلد الوظيفة app/controllers/comments_controller.rb المتحكّم الخاص بالتعليقات /app/views/comments يتم تخزين العروض الخاصّة بالتعليقات في هذا المجلد test/controllers/comments_controller_test.rb ملف الاختبار الخاصّ بالمتحكّم app/helpers/comments الملف الخاصّ بمساعد العرض app/assets/javascripts/comments.coffee ملف CoffeScript الخاصّ بالمتحكّم app/assets/stylesheets/comments.scss أوراق الأنماط المتتالية CSS الخاصّة بالمتحكّم كما هو الحال مع أي مدوّنة، فإن القرّاء سيكتبون تعليقاتهم بعد قراءة المقالة مباشرة، وبعد أن يرسلوا تعليقاتهم يتم توجيههم إلى صفحة عرض المقالة ليتمكّنوا من مشاهدة التعليقات. وستكون وظيفة المتحكّم CommentsController هي توفير التوابع اللازمة لإنشاء التعليقات وحذف التعليقات المزعجة حال وصولها. سنقوم أولًا بتعديل قالب عرض المقالات app/views/articles/show.html.erb لنتمكن من إضافة تعليق جديد: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> ستضيف الشيفرة السابقة استمارة إلى صفحة عرض المقالات يمكن من خلالها إضافة تعليق جديد من خلال استدعاء الحدث create ضمن المتحكّم CommentsController. ويستخدم الاستدعاء form_for مصفوفة ستعمل على إنشاء مسار متداخل nested route مثل: /articles/1/comments. لنجرِ الآن التعديلات اللازمة على الحدث create في الملفّ app/controllers/comments_controller.rb: class CommentsController < ApplicationController def create @article = Article.find(params[:article_id]) @comment = @article.comments.create(comment_params) redirect_to article_path(@article) end private def comment_params params.require(:comment).permit(:commenter, :body) end end ستتعقّد الأمور هنا قليلًا وذلك بسبب التداخل nesting الحاصل بين المسارات، إذ في كل مرة يتمّ فيها طلب تعليق معيّن يجب أن يتابع ذلك الطلب المقالة التي يرتبط بها هذا التعليق، وبالتالي استدعاء التابع find في نموذج Article والمسؤول عن اختيار المقالة المطلوبة حسب المعرّف المحدّد في المسار. بالإضافة إلى ذلك، استفدنا من بعض التوابع التي تقدّمها عملية الربط بين النموذجين، فقد استخدمنا التابع create على @article.comments لإنشاء التعليق وحفظه، وسيؤدي هذا إلى ربط التعليق الجديد بالمقالة المحدّدة. وبعد إنشاء التعليق الجديد نعيد توجيه المستخدم إلى المقالة الأصلية باستخدام الدالة المساعد article_path(@article). وكما شاهدنا تستدعي هذه الدالة الحدث show ضمن المتحكّم ArticlesController والذي يعمل بدوره على تصيير القالب show.html.erb، وهو المكان الذي نرغب أن تظهر التعليقات فيه؛ لذا سنقوم بإجراء التعديلات اللازمة على الملف app/views/articles/show.html.erb. <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <h2>Comments</h2> <% @article.comments.each do |comment| %> <p> <strong>Commenter:</strong> <%= comment.commenter %> </p> <p> <strong>Comment:</strong> <%= comment.body %> </p> <% end %> <h2>Add a comment:</h2> <%= form_for([@article, @article.comments.build]) do |f| %> <p> <%= f.label :commenter %><br> <%= f.text_field :commenter %> </p> <p> <%= f.label :body %><br> <%= f.text_area :body %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Edit', edit_article_path(@article) %> | <%= link_to 'Back', articles_path %> أصبح بإمكانك الآن إضافة المقالات والتعليقات إلى مدوّنتك وعرضها في الأماكن الصحيحة. في الدرس القادم سنكمل العمل على التعليقات، حيث سنستخدم الملفات الجزئية لترتيب القوالب أوّلًا، ثم نضيف إمكانية حذف التعليقات من قاعدة البيانات، وفي الختام سنتطرّق إلى عملية الاستيثاق Authentication بصورة سريعة ومبسّطة. المصدر: توثيقات Ruby on Rails.
  3. تعرّفنا في الدرس السابق بإيجاز على طريقة عمل إطار العمل Ruby on Rails حيث تعرّفنا على المتحكّمات والعروض وبدأنا بإنشاء تطبيق المدوّنة البسيطة وأنشأنا في الدرس السابق الاستمارة الخاصة بإضافة مقالة جديدة، ولكن وصلنا إلى النقطة التي نحتاج فيها إلى تخزين المقالة في قاعدة البيانات، وهنا يأتي دور النماذج Models. تحمل النماذج في Rails اسمًا بصيغة المفرد في حين يحمل الجدول المرتبط بها في قاعدة البيانات اسمًا بصيغة الجمع. تتيح أداة المولّد generator في Rails إنشاء النماذج ويلجأ أغلب المطوّرين إلى هذه الأداة لإنشاء النماذج. لإنشاء نموذج جديد استخدم الأمر التالي في سطر الأوامر: $ bin/rails generate model Article title:string text:text من خلال هذه الأمر نخبر Rails بأننا نرغب في إنشاء نموذج باسم Article إلى جانب خاصّية title من نوع string، وخاصّية text من نوع text. تضاف هذه الخواص بصورة تلقائية إلى جدول المقالات في قاعدة البيانات ويتم ربطها بنموذج Article. ويستجيب Rails لهذا الأمر بإنشاء عدد من الملفات، وما يهمّنا منها الآن هما app/models/article.rb و db/migrate/20140120191729_create_articles.rb (لاحظ أن اسم الملف الثاني يختلف قليلًا عن هذا الاسم). الملف الثاني مسؤول عن إنشاء بنية قاعدة البيانات، وهو ما سنتحدث عنه بعد قليل. إجراء عملية التهجير Migration كما لاحظنا فإن الأمر bin/rails generate model قد أنشأ ملف تهجير لقاعدة البيانات داخل المجلد db/migrate. والتهجيرات هي عبارة عن أصناف مصمّمة لتسهيل عملية إنشاء الجداول في قواعد البيانات والتعديل عليها. يستخدم Rails أوامر rake لإجراء التهجيرات، ويمكن التراجع عن عملية التجهير بعد إجرائها على قاعدة البيانات. تتضمّن أسماء ملفات التهجير ختمًا زمنيًا لضمان معالجة هذه الملفات حسب التسلسل الزمني لإنشائها. لو ألقينا نظرة في ملف db/migrate/YYYYMMDDHHMMSS_create_articles.rb (تذكّر أن الملف عندك يحمل ختمًا زمنيًّا مختلفًا) فسنجد التالي: class CreateArticles < ActiveRecord::Migration[5.0] def change create_table :articles do |t| t.string :title t.text :text t.timestamps end end end ستنشئ عملية التهجير أعلاه تابعًا يحمل اسم `change` والذي يتم استدعاؤه عند إجراء عملية التهجير. حتى الحدث المُعرّف ضمن التابع قابل للتراجع، ما يعني أن Rails قادر على التراجع عن التغييرات الحاصلة من إجراء عملية التهجير في حال أردت ذلك في وقت لاحق. عند إجراء عملية التهجير هذه سيتم إنشاء جدول باسم `articles` يتضمن عمودًا من نوع `string` وآخر من نوع `text`، إضافة إلى عمودين للختم الزمني يمكن لـ Rails من خلالهما متابعة تواريخ إنشاء وتعديل المقالات. لتنفيذ عمية التهجير توجّه إلى سطر الأوامر ونفذ الأمر التالي: $ bin/rails db:migrate سينفّذ Rails أمر التهجير التالي وسيخبرك بإنشاء جدول Articles. == CreateArticles: migrating ================================================== -- create_table(:articles) -> 0.0019s == CreateArticles: migrated (0.0020s) ========================================= حفظ البيانات بواسطة المتحكّم سنعود الآن إلى المتحكّم ArticlesController، حيث سنعمل على تعديل الحدث create ليستخدم النموذج الجديد Article لحفظ البيانات في قاعدة البيانات. افتح الملف app/controllers/articles_controller.rb وعدّله بالصورة التالية: def create @article = Article.new(params[:article]) @article.save redirect_to @article end يمكن استحداث initialize كل نموذج في Rails مع الخصائص Attributes المرتبطة به، والتي يتم ربطها تلقائيًا مع الأعمدة المقابلة في قاعدة البيانات. وقد قمنا بذلك في السطر الأول في الحدث create (هل تذكر params[:article] والذي يضمّ الخصائص التي نريدها). بعد ذلك يمكن حفظ النموذج في قاعدة البيانات من خلال الدالة @article.save. وفي النهاية نعيد توجيه المستخدم إلى الحدث show الذي سنعرّفه في وقت لاحق. توجّه الآن إلى العنوان http://localhost:3000/articles/new وستتلقّى الخطأ التالي: يدعم Rails العديد من مزايا الأمان التي تساعد في كتابة تطبيقات أمينة، ونحن الآن نتعامل مع إحدى هذه المزايا. تدعى هذه الميزة بالمعاملات القوية strong parameters والتي تجبرنا على تحديد المعاملات المسموح بها في الأحداث الموجودة ضمن المتحكم. ما الفائدة من ذلك؟ صحيح أن القدرة على إضافة جميع المعاملات إلى النموذج دفعة واحدة وبصورة تلقائية يختصر الكثير من الجهد بالنسبة للمبرمج، إلا أنّ البرنامج يكون في هذه الحالة عرضة للاستخدامات الخبيثة. فماذا لو تمّ إنشاء طلب إلى الخادوم يتضمن استمارة إنشاء مقالة جديدة إضافة إلى حقول أخرى تحتوي على معلومات تضرّ بالتطبيق؟ سيتم إسناد المعلومات الإضافية بصورة شاملة “Mass Assignment” إلى النموذج ثم إلى قاعدة البيانات جنبًا إلى جنب مع البيانات الأصلية، وهذا قد يتسبب في تعطيل عمل برنامجك أو قد يحدث ما هو أسوأ من ذلك بكثير. يجب علينا إذًا تحديد المعاملات المسموح بإدخالها إلى النموذج، وفي حالتنا هذه سنسمح بإدراج معاملي title و text ونطلب توفّر قيم لهما. وللقيام بذلك عدّل السطر الأول من حدث create بالصورة التالية: @article = Article.new(params.require(:article).permit(:title, :text)) غالبًا ما يتمّ تحديد المعاملات المسموح بإدخالها إلى النموذج في تابع خاص ليصبح بالإمكان إعادة استخدامها بواسطة عدة أحداث في المتحكّم نفسه مثل حدثي create و update، إضافة إلى ذلك يكون هذا التابع خاصًّا وذلك باستخدام المحدّد private لضمان عدم إمكانية استدعائه من خارج السياق المقرّر له، وبالشكل التالي: def create @article = Article.new(article_params) @article.save redirect_to @article end private def article_params params.require(:article).permit(:title, :text) end عرض المقالات إن قمت بتعبئة استمارة المقالة الجديدة وإرسالها فستتلقّى خطأ مفاده عدم عثور Rails على الحدث show، لذا سنقوم بإنشاء هذا الحدث الآن. كما رأينا سابقًا في مخرجات الأمر bin/rails routes فإن مسار الحدث show هو: article GET /articles/:id(.:format) articles#show تعني الصيغة الخاصة :id أن هذا المسار يطلب وجود معامل :id والذي يمثّل في حالتنا هذه معرّف المقالة. وكما فعلنا سابقًا، يجب علينا إضافة الحدث show إلى ملف المتحكّم app/controllers/articles_controller.rb وتحديد العرض المرتبط به. عادة ما تأخذ أحداث CRUD في المتحكّمات الترتيب التالي: index, show, new, edit, create, update, destroy. ويمكن اتّباع الترتيب الذي يعجبك، ولكن تذكّر أن هذه التوابع هي توابع عامّة public، ويجب الإعلان عنها قبل الإعلان عن التوابع الخاصّة. سنضيف الآن الحدث show آخذين ما سبق بعين الاعتبار: class ArticlesController < ApplicationController def show @article = Article.find(params[:id]) end def new end # بقيّة الشيفرة ..... استخدمنا الدالة Article.find للبحث عن المقالة المطلوبة، وذلك بتمرير المعامل params[:id] للحصول على قيمة المعرّف من الطلب الذي أرسلته صفحة إنشاء مقالة جديدة. كذلك استخدمنا متغيّرًا من نوع instance (مسبوقًا بعلامة @) ليكون مرجعًا لكائن المقالة، وذلك لأنّ Rails يمرّر هذا النوع من المتغيّرات إلى العرض. أنشئ الآن ملفًّا جديدًا باسم show.html.erb في المسار app/views/articles/ وأضف إليه الشيفرة التالية: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> ستكون الآن قادرًا على إنشاء مقالة جديدة؛ لذا توجّه إلى العنوان http://localhost:3000/articles/new وجرّب إضافة مقالة جديدة. عرض قائمة بمقالات المدوّنة نحتاج الآن إلى عرض قائمة بجميع المقالات الموجودة في المدونة، وسيكون المسار المرتبط بهذا الحدث وبحسب مخرجات الأمر bin/rails routes كالتالي: articles GET /articles(.:format) articles#index أضف الحدث index المرتبط بهذا المسار إلى المتحكّم ArticlesController في الملف app/controllers/articles_controller.rb. من الممارسات الشائعة بين المطوّرين هو كتابة الحدث index في بداية المتحكّم: class ArticlesController < ApplicationController def index @articles = Article.all end def show @article = Article.find(params[:id]) end def new end # بقية الشيفرة ... بعدها أضف العرض الخاصّ بهذا الحدث والموجود في المسار app/views/articles/index.html.erb والذي يتضمّن الشيفرة التالية: <h1>Listing articles</h1> <table> <tr> <th>Title</th> <th>Text</th> </tr> <% @articles.each do |article| %> <tr> <td><%= article.title %></td> <td><%= article.text %></td> <td><%= link_to 'Show', article_path(article) %></td> </tr> <% end %> </table> توجّه الآن إلى العنوان http://localhost:3000/articles في المتصفّح وستشاهد قائمة بجميع المقالات التي أنشأتها مسبقًا. إضافة الروابط للتنقل بين صفحات المدوّنة أصبح بمقدورنا الآن إنشاء وعرض وسرد قائمة المقالات المتوفّرة في المدونة، ولكنّنا بحاجة إلى بعض الروابط التي تساعدنا في التنقل بين صفحات الموقع. افتح الملف app/views/welcome/index.html.erb وعدّله كما يلي: <h1>Hello, Rails!</h1> <%= link_to 'My Blog', controller: 'articles' %> التابع link_to هو أحد دوال العروض المساعدة والمضمّنة في Rails، ووظيفة هذا التابع إنشاء رابط تشعّبي بالاستناد إلى النصّ الذي نمرّره إليه، وهو في حالتنا هذه المسار الخاص بسرد قائمة المقالات. لنضف بعض الروابط إلى العروض الأخرى، ولنبدأ بإضافة رابط إنشاء مقالة جديدة إلى الملف app/views/articles/index.html.erb قبل وسم <table>: <%= link_to 'New article', new_article_path %> سيوجّه هذا الرابط المستخدم إلى الصفحة التي تتضمن استمارة إنشاء مقالة جديدة. سنضيف رابطًا آخر إلى الملفّ app/views/articles/new.html.erb بعد الاستمارة مباشرة، ليتمكن المستخدم من العودة إلى الصفحة الرئيسية: <%= form_for :article, url: articles_path do |f| %> ... <% end %> <%= link_to 'Back', articles_path %> وأخيرًا، سنضيف رابطًا إلى القالب app/views/articles/show.html.erb يوجّه المستخدم إلى الصفحة الرئيسية أيضًا، وبهذا يصبح بميسور من يستعرض مقالة معيّنة أن يرجع إلى الصفحة التي تعرض جميع المقالات: <p> <strong>Title:</strong> <%= @article.title %> </p> <p> <strong>Text:</strong> <%= @article.text %> </p> <%= link_to 'Back', articles_path %> التحقّق من المدخلات لو نظرت إلى النموذج الذي أنشأناه سابقًا فسترى أنّ الملف بسيطٌ للغاية: class Article < ApplicationRecord end لاحظ أنّ الصنف Article موروث من الصنف ApplicationRecord وهو بدوره موروث من الصنف ActiveRecord::Base والذي يتضمّن الكثير من الوظائف والإجراءات الخاصة بالنماذج، مثل عمليات CRUD البسيطة (Create, Read, Update, Destroy) والتحقّق من البيانات Validation، إضافة إلى عمليات البحث المعقّدة وربط النماذج المختلفة مع بعضها البعض. ويقدّم إطار العمل Rails توابع متعدّدة تساعد في التحقق من البيانات المرسلة إلى النموذج. افتح الملف app/models/article.rb وأضف إليه الشيفرة التالية: class Article < ApplicationRecord validates :title, presence: true, length: { minimum: 5 } end سيضمن هذا التغيير امتلاك كل مقالة جديدة في المدونة لعنوان يتألف من خمسة أحرف على الأقل. يتيح Rails التحقّق من أمور متنوّعة في النماذج، مثل التحقّق من وجود أو عدم تكرار الأعمدة والتحقّق من تنسيقها ووجود كائنات مرتبطة بها. لنجرّب الآن استدعاء الدالة @article.save في مقالة لا تمتلك عنوانًا وسنلاحظ أن الدالة ترجع القيمة false. لو عدنا إلى المتحكّم في الملف app/controllers/articles_controller.rb مرّة أخرى سنلاحظ بأنّنا لم نتحقّق من النتيجة التي ترجعها الدالة @article.save ضمن الحدث create. إن فشلت الدالة @article.save في أداء عملها، يجب أن نعيد المستخدم إلى استمارة إضافة مقالة جديدة، وللقيام بذلك عدّل حدثي new و create في الملف app/controllers/articles_controller.rb بالصورة التالية: def new @article = Article.new end def create @article = Article.new(article_params) if @article.save redirect_to @article else render 'new' end end private def article_params params.require(:article).permit(:title, :text) end سينشئ الحدث new متغيّرًا جديدًا من نوع instance يحمل الاسم @article وستتعرّف إلى سبب القيام بذلك بعد قليل. لاحظ أنّنا استخدمنا render داخل الحدث create بدلًا من redirect_to في حال إرجاع الدالة save للقيمة false. يستخدم التابع render لكي يتم تمرير الكائن @article إلى القالب الجديد عند تصييره. وعملية التصيير هذه تتم ضمن نفس الطلب الناتج من إرسال الاستمارة، في حين أن الدالة redirect_to تتسبّب في إرسال طلب آخر. الآن أعد تحميل الصفحة ذات العنوان http://localhost:3000/articles/new وحاول إضافة مقالة جديد دون عنوان، سترى بأنّ Rails يعيدك إلى صفحة الاستمارة، ولكن هذا ليس مفيدًا جدًّا. يجب إخبار المستخدم بحدوث خطأ ما، وللقيام بذلك عدّل الملف app/views/articles/new.html.erb للتحقّق من رسائل الخطأ: <%= form_for :article, url: articles_path do |f| %> <% if @article.errors.any? %> <div id="error_explanation"> <h2> <%= pluralize(@article.errors.count, "error") %> prohibited this article from being saved: </h2> <ul> <% @article.errors.full_messages.each do |msg| %> <li><%= msg %></li> <% end %> </ul> </div> <% end %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> <%= link_to 'Back', articles_path %> تحقّقنا في البداية من وجود أي أخطاء من خلال @article.errors.any?، وفي حال وجودها نعرض قائمة الأخطاء المتوفّرة من خلال @article.errors.full_messages. تأخذ الدالة pluralize معاملين الأول رقمي والثاني نصّي. إن كان العدد أكبر من واحد تتحوّل السلسلة النصّية تلقائيًا إلى صيغة الجمع. إن سبب إضافة @article = Article.new إلى المتحكّم ArticlesController هو أنّنا لو لم نقم بذلك لأصبحت قيمة المتغيّر @articl هي nil، وسيؤدي الاستدعاء @article.errores.any? إلى إطلاق خطأ. يحيط Rails الحقول التي تحتوي على أخطاء بوسم <div> مع صنف CSS يحمل الاسم field_with_errors، ويمكنك تعريف صنف CSS هذا لتنسيق الحقول حسب الرغبة. والآن ستتلقّى رسالة خطا مرتّبة عندما تحاول حفظ مقالة لا تتضمن عنوانًا. في الدرس القادم سنواصل العمل على النموذج حيث سنكتب الشيفرة المسؤولة عن تعديل المقالات وحذفها، ثم سنتعرّف على طريقة إنشاء علاقات بين النماذج المختلفة من خلال إضافة نموذج للتعامل مع التعليقات في المدونة. المصدر: توثيقات Ruby on Rails.
  4. Rails هو إطار عمل لتطوير تطبيقات الويب مكتوب بلغة Ruby البرمجية، وقد صُمّم إطار العمل هذا لتسهيل برمجة تطبيقات الويب من خلال وضع بعض الافتراضات المسبقة حول ما يحتاجه المطوّر للشروع في العمل. يتيح إطار العمل هذا كتابة شيفرات أقل وإنجاز أمور أكثر من أي لغة برمجية أو أطر عمل أخرى. يفترض Rails أن هناك طريقة مثلى لإنجاز الأعمال، وقد صمّم لتشجيع المطوّر على اتباع هذه الطرق وفي بعض الأحيان حثّه على ترك البدائل الأخرى، وقد تلاحظ زيادة هائلة في إنتاجيتك إن تعلّمت الأسلوب الذي يتبعه إطار العمل هذا، وقد يؤدي الالتزام بالعادات القديمة المتّبعة في لغات البرمجة الأخرى إلى تجربة غير جيّدة في تطوير التطبيقات باستخدام Rails. تستند فلسفة Rails إلى ركيزتين أساسيتين: لا تكرّر نفسك (Don’t Repeat Yourself): ينصّ هذا المفهوم على وجوب تمثيل أي جزء من أجزاء المعرفة بصورة مفردة وغير مبهمة وموثوقة في النظام. اتّباع هذا المفهوم في كتابة النصوص البرمجية وعدم تكرار المعلومات ذاتها باستمرار يؤدي إلى زيادة قابلية صيانة الشيفرة المكتوبة وامتلاكها القدرة على التوسّع إضافة إلى انخفاض نسبة الأخطاء فيها. مبدأ “Convention Over Configuration”: يمتلك Rails مبادئ خاصّة ترتبط بتحديد الطريقة المثلى في إنجاز الأعمال في تطبيق الويب، ويعتمد على هذه المبادئ بصورة افتراضية بدلًا من إجبار المطوّر على تحديد تفاصيل صغيرة في عمله من خلال عدد كبير من اﻹعدادات. ما الذي تحتاجه للبدء هذه السلسلة مخصصة للمبتدئين الذين يرغبون في الشروع ببناء التطبيقات على إطار العمل Rails، ولا يفترض وجود أي خبرة سابقة في هذا المجال، ولكن هناك بعض الأمور التي يجب تثبيتها قبل الشروع في التعلم: تثبيت الإصدار 2.2.2 من لغة Ruby البرمجية أو أي إصدار أعلى. تثبيت النسخة الملائمة من حزمة التطوير Development Kit إن كنت من مستخدمي نظام التشغيل ويندوز. نظام إدارة الحزم (الجواهر) RubyGems والذي يأتي مع لغة Ruby بصورة افتراضية. تثبيت قواعد بيانات SQLite3. ذكرنا أنّ إطار العمل Rails مبني باستخدام لغة Ruby البرمجية، وإن كنت لا تمتلك خبرة مسبقة بهذه اللغة يمكنك مراجعة الدروس المتوفّرة حول أساسيات لغة Ruby في الأكاديمية إضافة إلى الموقع الرسمي للغة. إنشاء مشروع جديد في Rails الهدف من هذه السلسلة هو بناء مدوّنة بسيطة باستخدام إطار العمل Rails، وقبل البدء في بناء التطبيق يجب التأكد من تثبيت Rails في جهازك. سنستخدم الرمز $ للتعبير عن سطر الأوامر في الأنظمة الشبيهة بـ UNIX. أما في نظام ويندوز فسترى سطر الأوامر يبدأ بشيء مشابه لهذه الصيغة: <C:\source_code. تثبيت Rails توجّه إلى سطر الأوامر في جهازك (في نظام macOS افتح الطرفية Terminal.app، وفي نظام ويندوز اختر “Run” من قائمة ابدأ ثم اكتب cmd.exe). في البداية سنتأكد من إصدار لغة Ruby المثبت في الجهاز: $ ruby -v ruby 2.3.1p112 بالنسبة لقواعد البيانات SQLite3 فعادة ما تكون مثبّتة بشكل افتراضي في الأنظمة الشبيهة بـ UNIX. أما في نظام ويندوز، فإن قمت بتثبيت Rails من خلال مثبت Rails فإن SQLite ستكون مثبتة على جهازك أيضاً. يمكنك كذلك مراجعة موقع SQLite3 للاطلاع على تعليمات تثبيت قاعدة البيانات. يمكن التحقق من سلامة تثبيت SQLite3 من خلال الأمر التالي: $ sqlite3 --version إن كانت SQLite مثبتة في الجهاز فسيظهر رقم الإصدار المثبت في سطر الأوامر. لتثبيت Rails استخدم أمر التثبيت gem install الذي يتيحه RubyGems وبالصورة التالية: $ gem install rails وللتأكد من أن عملية التثبيت قد تمّت بصورة صحيحة، يجب أن تكون قادرًا على تنفيذ الأمر التالي في سطر الأوامر: $ rails --version يجب أن تحصل على نتيجة مشابهة لهذه: Rails 5.1.0. إنشاء تطبيق المدوّنة يقدّم إطار العمل Rails مجموعة من الشيفرات تحمل اسم المولّدات generators، وتهدف هذه الشيفرات إلى تسهيل عمل المطوّر من خلال إنشاء الملفات المطلوبة للشروع في مهمّة معيّنة. مولّد التطبيق الجديد هو أحد هذه المولّدات ويعمل على إنشاء تطبيق Rails جديد وتوفير عناء كتابته من قبل المطور. ولاستخدام المولّد توجّه في سطر الأوامر إلى المجلد الذي ترغب في إنشاء التطبيق فيه واكتب الأمر التالي: $ rails new blog سينشئ هذا الأمر تطبيقًا جديدًا باسم Blog في مجلد blog وسيثبت اعتماديات gem الموجودة في GEMfile باستخدام الأمر bundle install. يمكنك الاطلاع على جميع الخيارات المتاحة في سطر الأوامر والتي يتقبّلها مولّد تطبيقات Rails وذلك من خلال تنفيذ الأمر: rails new -h بعد إنشاء تطبيق المدوّنة، توجّه في سطر الأوامر إلى المجلّد الخاص به: $ cd blog ستلاحظ أنّ مجلّد المدونة يتضمن بعض الملفات والمجلّدات التي تم إنشاؤها بصورة تلقائية والتي تمثّل العمود الفقري لتطبيق Rails. سينحصر الجزء الأكبر من عملنا ضمن مجلد app، ولكن لا بأس في الاطلاع بصورة سريعة على وظيفة هذه الملفات والمجلّدات: الملف أو المجلد الوظيفة /app يتضمن هذا المجلّد: المتحكّمات controllers، النماذج models، العروض views، الدوال المساعدة helpers، دوال البريد اﻹلكتروني mailers، القنوات channels، الوظائف jobs، والأصول assets الخاصّة بالتطبيق. سيتركّز عملنا ضمن هذا المجلد. /bin يتضمّن هذا المجلد شيفرات Rails المسؤولة عن تشغيل التطبيق ويمكن أن يتضمن شيفرات أخرى تستخدم في تثبيت وتحديث ونشر وتشغيل التطبيق. /config يتضمن الإعدادات الخاصة بمسارات التطبيق routes، وقاعدة البيانات وغير ذلك config.ru ملف إعدادات Rack يستخدم في خواديم Rack لتشغيل التطبيق عليها. /db يتضمّن مخطط قاعدة البيانات الحالية، إضافة إلى تهجيرات قاعدة البيانات. Gemfile, Gemfile.lock يتيح هذان الملفان تحديد اعتماديات gem المطلوبة لتطبيق Rails. يستخدم Bundler هذه الملفات. لمزيد من المعلومات توجّه إلى موقع Bundler الإلكتروني. /lib الوحدات الموسّعة الخاصة بالتطبيق. /log ملفات log الخاصة بالتطبيق. /public المجلد الوحيد الذي سيظهر على حاله بعد نشر التطبيق، ويتضمن الملفات الساكنة و ملفات الأصول المجمّعة. Rakefile يحدّد هذا الملف ويحمّل المهامّ التي يمكن تنفيذها بواسطة سطر الأوامر. يتم تعريف المهامّ ضمن مكوّنات Rails. ولإضافة مهامّ جديدة يجب عدم تعديل هذا الملف، بل إضافة ملفات إلى مجلّد lig/tasks. README.md الملفّ التعريفي الخاصّ بالتطبيق، ويمكن من خلاله تقديم نبذة تعريفية عن التطبيق والمهام التي يؤديها وطريقة التثبيت وغير ذلك من المعلومات. /test يضمّ هذا المجلد جميع الأمور المرتبطة بالاختبارات. /tmp يضمّ هذا المجلّد الملفّات المؤقتة (مثل ملفات الذاكرة المخبئية وملفات pid). /vendor ستجد هنا جميع شيفرات الطرف الثالث، وعادة ما يتضمن جواهر مطوّرة من قبل أشخاص أو شركات. gitignore. يخبر هذا الملف نظام التحكم في النسخ Git عن الملفات أو (الأنماط) التي ينبغي عليه تجاهلها. لتعرف المزيد راجع سلسلة دروس Git في الأكاديمية. مرحبًا Rails لنحاول في البداية إظهار بعض النصوص على الشاشة وبصورة سريعة، وللقيام بذلك، ستحتاج إلى تشغيل الخادوم الخاص بـ Rails. تشغيل خادوم Rails يتضمّن إطار العمل Rails خادوم ويب خاصًّا به وكل ما نحتاج إليه هو تشغيله وذلك من خلال تنفيذ الأمر التالي في سطر الأوامر ضمن مجلد blog: $ bin/rails server إن كنت تستخدم نظام ويندوز يجب تمرير الشيفرات في مجلد bin إلى مفسّر Ruby مباشرة: ruby bin\rails server تنفيذ هذا الأمر سيؤدي إلى تشغيل Puma، وهو خادوم ويب مضمّن بصورة افتراضية في إطار العمل Rails. حان الآن وقت الولوج إلى تطبيقنا من خلال المتصفح وذلك بالتوجه إلى الرابط http://localhost:3000/. ستظهر الصفحة التالية لتشير إلى نجاحنا في إنشاء أول مشروع على Ruby on Rails. المصدر: توثيقات Ruby on Rails.
  5. تعرّفنا في الدرس السابق على طريقة تثبيت إطار العمل Rails وبدأنا العمل على مشروعنا الأول وهو عبارة عن مدوّنة بسيطة، وقمنا بتشغيل الخادوم الخاص بإطار العمل. وفي هذا الدرس سنتعرّف على آلية عمل إطار العمل Rails من خلال مثال بسيط، ثم نشرع بعده ببناء مدونتنا البسيطة لنتعرف بصورة أكبر على العديد من المفاهيم التي يستند إليها هذا الإطار. آلية عمل إطار Rails سنتعرّف على آلية عمل إطار Ruby on Rails من خلال مثال بسيط نعرض فيه مجموعة من الكلمات في الصفحة الرئيسية لتطبيقنا، وللقيام بذلك سنحتاج إلى متحكّم Controller وعرض View. وظيفة المتحكّم هي استقبال الطلبات الواردة إلى التطبيق، وتربط المسارات Routes بين الطلبات والمتحكّمات. وغالبًا ما يكون هناك أكثر من مسار واحد لكل متحكّم، ويمكن للمسارات المختلفة أن تؤدّي إلى أحداث Actions مختلفة، ووظيفة الحدث هي جمع المعلومات اللازمة وتقديمها إلى العرض. أمّا وظيفة العرض فواضحة من اسمه، وهي عرض المعلومات التي حصل عليها من الحدث بصورة مقروءة للإنسان. من الضروري هنا الانتباه إلى أن عملية جمع المعلومات تتمّ ضمن المتحكّم وليس ضمن العرض، ومهمّة العرض الوحيدة هي عرض المعلومات. يستخدم إطار Rails لغة قوالب خاصّة في العروض تدعى eRuby (اختصار لـ Embedded Ruby) والتي تُعالج بواسطة دورة الطلب في Rails قبل أن تُرسل إلى المستخدم. سلنجأ إلى أداة المولّد generator لإنشاء متحكّم يحمل اسم Welcome يتضمّن حدثًا باسم index. اكتب الأمر التالي في سطر الأوامر: $ bin/rails generate controller Welcome index سيقوم Rails بإنشاء مسار وعدد من الملفات. create app/controllers/welcome_controller.rb route get 'welcome/index' invoke erb create app/views/welcome create app/views/welcome/index.html.erb invoke test_unit create test/controllers/welcome_controller_test.rb invoke helper create app/helpers/welcome_helper.rb invoke test_unit invoke assets invoke coffee create app/assets/javascripts/welcome.coffee invoke scss create app/assets/stylesheets/welcome.scss ما يهمّنا من هذه الملفات هما المتحكم والموجود في المسار app/controllers/welcome_controller.rb والعرض الموجود في المسار app/views/welcome/index.html.erb. افتح الملف app/views/welcome/index.html.erb في محرّر النصوص المفضّل لديك، واحذف محتوياته واستبدلها بالشيفرة التالية: <h1>Hello, Rails!</h1> بعد أن أنشئنا المتحكم والعرض يجب علينا إخبار Rails بالمسار الذي سيأخذ المستخدم إلى هذا العرض. نحن نرغب في حالتنا هذه أن يتم توجيه المستخدم إلى العرض عندما يتوجّه إلى العنوان http://localhost:3000، ولكن صفحة الترحيب تشغل هذا المسار في الوقت الحاضر. بعد ذلك يجب إخبار Rails بموقع الصفحة الرئيسية ليتمكّن من عرضها للمستخدم. افتح الملف config/routes.rb في محرّر النصوص: Rails.application.routes.draw do get 'welcome/index' # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html end الشيفرة أعلاه موجودة في ملف المسارات والذي يتضمّن مدخلات DSL خاصّة (DSL اختصار لـ domain-specific language) والتي تخبر Rail بطريقة ربط الطلبات الواردة إلى التطبيق بالمتحكمات والأحداث. عدّل هذا الملف بالصورة التالية: Rails.application.routes.draw do get 'welcome/index' root 'welcome#index' end من خلال السطر root 'welcome#index' يربط إطار العمل Rails الطلبات الواردة إلى المسار الرئيسي في التطبيق مع الحدث index في المتحكّم Welcome، أما السطر get 'welcome/index' فيربط من خلاله Rails الطلبات الواردة إلى العنوان http://localhost:3000/welcome/index بنفس الحدث ونفس المتحكّم، وقد تمّ إنشاء هذه الشيفرة من قبل أداة المولّد. والآن شغّل الخادوم الخاص بـ Rails ثمّ توجّه في المتصفّح إلى العنوان http://localhost:3000، وستشاهد عبارة “Hello, Rails!” الموجودة في ملف app/views/welcome/index.html.erb وهذا يعني أن هذا المسار قد توجّه فعلًا إلى الحدث index في المتحكم Welcome والذي قام بدوره بتصيير العرض بصورة صحيحة. البدء بإنشاء المدوّنة بعد أن تعرّفنا على المتحكّمات والأحداث والعروض، لنبدأ العمل على مدوّنتنا. سننشئ الآن ما يسمى في إطار العمل Rail بالمورد resourse، والمورد هو مصطلح يعبّر عن مجموعة من العناصر المتشابهة، مثل المقالات، الأشخاص أو الحيوانات. ويمكن إنشاء create وقراءة read وتحديث update وإلغاء destroy العناصر في المورد، وتسمى هذه العمليات بعمليات CRUD. يقدّم Rails تابعًا باسم resources يمكن استخدامه للإفصاح عن مورد بنمط REST القياسي. يجب إضافة مورد المقالة إلى ملف config/routes.rb وكما يلي: Rails.application.routes.draw do get 'welcome/index' resources :articles root 'welcome#index' end والآن إن قمت بتنفيذ الأمر bin/rails routes فستشاهد جميع المسارات الخاصّة بجميع الأحداث التي تتّصف بنمط REST. سنتعرّف على معنى عمود prefix وبقية الأعمدة في وقت لاحق، ولكن لاحظ أنّ Rails قد خمّن صيغة المفرد (article) واستخدمها في السياق الصحيح. $ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index سنعمل الآن على إضافة خاصيتي إنشاء المقالات وعرضها، وستكون الاستمارة Form المسؤولة عن ذلك بالشكل التالي: قد تبدو الاستمارة بدائيًّة ولكنّها كافية في الوقت الحاضر، وسنعمل على تحسين مظهرها فيما بعد. إنشاء المتحكّمات والمسارات اللازمة في البداية يجب اختيار المسار الذي سيوجّه المستخدم إلى استمارة إنشاء المقالة الجديدة، وسنستخدم المسار /articles/new للقيام بهذه المهمّة، بعدها يصبح بميسور التطبيق أن يتلقّى الطلبات على هذا المسار. توجّه الآن في متصفحك إلى الرابط http://localhost:3000/articles/new وستتلقّى الخطأ التالي: يحدث هذا الخطأ لأنّ المسار بحاجة إلى متحكّم يرسل إليه الطلب؛ لذا سنقوم بإنشاء متحكّم باسم ArticlesController، وذلك من خلال تنفيذ الأمر التالي: $ bin/rails generate controller Articles افتح الملف الذي قمت بإنشائه app/controllers/articles_controller.rb وسترى متحكّمًا فارغًا: class ArticlesController < ApplicationController end المتحكّم عبارة عن صنف Class موروث من ApplicationController وسنقوم بتعريف التوابع ضمن هذا الصنف والتي ستمثل الأحداث الخاصّة بهذا المتحكم، وهذه الأحداث هي المسؤولة عن تنفيذ عمليات CRUD على المقالات الموجودة في تطبيقنا. إن أعدت تحميل الصفحة ستتلقّى خطأً جديدًا: يشير هذا الخطأ إلى عدم قدرة Rails على إيجاد الحدث new ضمن المتحكّم ArticlesController الذي قمنا بإنشائه للتوّ. وهذا عائد إلى أنّ المتحكّمات تكون فارغة عند إنشائها إلا إذا حدّدنا الأحداث المطلوبة خلال عملية إنشاء المتحكّم. ولتعريف حدث جديد بصورة يدوية، سنحتاج فقط إلى تعريف تابع جديد ضمن المتحكم. افتح الملف app/controllers/articles_controller.rb وضمن الصنف ArticlesController عرّف تابعًا جديدًا وكما يلي: class ArticlesController < ApplicationController def new end end والآن أعد تحميل الصفحة في المتصفّح وستتلقّى خطأً آخر: يظهر هذا الخطأ لأنّ Rails يتوقّع أنه يجب أن تمتلك الأحداث الصرفة المشابهة لهذا الحدث عروضًا ترتبط معها لعرض المعلومات التي تتضمنها، ونظرًا لعدم وجود أي عرض مرتبط بهذا الحدث، أطلق Rails هذا الخطأ. لنطّلع على رسالة الخطأ الكاملة: لنستعرض النص السابق سريعًا، ونفهم مضمونه بصورة جيدة. يحدّد الجزء الأول من نصّ الخطأ القالب المفقود، وفي هذه الحالة القالب المفقود هو articles/new. يبدأ Rails بالبحث عن هذا القالب، وإن لم يفلح في العثور عليه فإنه يحاول تحميل قالب يدعى application/new وذلك لأنّ المتحكّم ArticleController هو صنف موروث من المتحكّم ApplicationController. يتضمن الجزء الثاني من رسالة الخطأ request.formats والذي يحدّد صيغة القالب الذي سيتم عرضه كاستجابة للطلب الذي تلقّاه التطبيق، وقد تم اختيار صيغة text/html لأنّنا طلبنا هذه الصفحة بواسطة المتصفح؛ لذا يبحث Rails عن قوالب HTML. أما request.variant فيحدد طبيعة الأدوات المادّية physical devices التي سيتم تقديمها مع الطلب وتساعد Rails في تحديد القالب الذي سيستخدمه في الاستجابة، وهو فارغ نظرًا لعدم توفّر المعلومات. أبسط قالب يمكن أن يعمل في هذه الحالة هو القالب الموجود في المسار app/views/articles/new.html.erb. هذه اللاحقة مهمّة للغاية: فالجزء الأول من اللاحقة (.html) يعبّر عن صيغة القالب، أمّا الجزء الثاني (.erb) فيمثّل المعالج handler الذي سيتم استخدامه في تصيير القالب. يحاول Rails البحث عن قالب يحمل الاسم articles/new ضمن المجلد app/views. يجب أن تكون صيغة هذا القالب هي HTML حصرًا، وسيكون erb المعالج الافتراضي لـ HTML. يستخدم Rails عددًا من المعالجات مثل: builder والمستخدم في إنشاء قوالب XML، وcoffee الذي يستخدم لغة CoffeeScript لبناء قوالب JavaScript. بما أنّنا نرغب في بناء استمارة HTML جديدة فسنستخدم لغة ERB والتي تتيح لنا تضمين لغة Ruby في HTML. إذًا سيكون اسم القالب articles/new.html.erb وسيكون ضمن المجلد app/views الخاص بالتطبيق. أنشئ ملفًّا جديدًا باسم new.html.erb في المسار app/views/articles وأضف إليه ما يلي: <h1>New Article</h1> أعد تحميل الصفحة وستلاحظ ظهور العنوان في رأس الصفحة، وهذا يعني أن هناك تناغمًا تامًّا بين كلّ من المسار والمتحكم والحدث والعرض. الاستمارة الأولى سنستخدم منشئ النماذج form builder لإنشاء الاستمارة الأولى في هذا القالب. يمكن استخدام منشئ النماذج الرئيسي في Rails باستخدام التابع المساعد form_for. أضف الشيفرة التالية في الملف app/views/articles/new.html.erb: <%= form_for :article do |f| %> <p> <%= f.label :title %><br> <%= f.text_field :title %> </p> <p> <%= f.label :text %><br> <%= f.text_area :text %> </p> <p> <%= f.submit %> </p> <% end %> أعد تحميل الصفحة وستلاحظ ظهور نفس الاستمارة التي عرضناها في المثال السابق. كما تلاحظ فإنّ بناء الاستمارات في Rails أمر سهلٌ للغاية. عندما نستدعي التابع form_for فإننا نمرّر إليه عنصرًا يحدّد الهدف من هذه الاستمارة، والهدف في حالتنا هذه هو :article. يُستخدم الكائن FormBuilder والذي مثّلناه بـ f لبناء عنصري label وحقلي نصوص text fields لكلّ من عنوان المقال ومتنها. وفي النهاية استدعينا التابع submit لإنشاء زرّ اﻹرسال الخاصّ بالاستمارة. ولكن تعاني هذه الاستمارة من مشكلة صغيرة. لو تفحّصت شيفرة HTML التي تم توليدها من خلال الشيفرة السابقة فستلاحظ أن خاصية action التابعة للاستمارة تشير إلى المسار articles/new وهذا المسار هو نفسه الذي يقودنا إلى هذه الصفحة، والمفروض أن يستخدم هذا المسار لعرض استمارة إنشاء مقالة جديدة لا غير. إذًا يجب أن تستخدم الاستمارة مسارًا آخر، ويمكن القيام بذلك بسهولة من خلال استخدام الخيار :url في form_for. عادة ما يحمل الحدث المسؤول عن إرسال مقال جديد اسم “create”، لذا يجب توجيه الاستمارة إلى هذا الحدث. عدّل السطر الذي يتضمن form_for في ملف app/views/articles/new.html.erb كما يلي: <%= form_for :article, url: articles_path do |f| %> في هذا المثال تم تمرير الدالة المساعدة articles_path إلى الخيار :url، ولنتعرّف على نتيجة هذا التعديل سنلقي نظرة على مخرجات الأمر bin/rails routes في سطر اﻷوامر: $ bin/rails routes Prefix Verb URI Pattern Controller#Action articles GET /articles(.:format) articles#index POST /articles(.:format) articles#create new_article GET /articles/new(.:format) articles#new edit_article GET /articles/:id/edit(.:format) articles#edit article GET /articles/:id(.:format) articles#show PATCH /articles/:id(.:format) articles#update PUT /articles/:id(.:format) articles#update DELETE /articles/:id(.:format) articles#destroy root GET / welcome#index توجّه الدالة المساعدة articles_pat الاستمارة إلى نمط URI المرتبط لاحقة articles وسيرسل الاستمارة - تلقائيًا - طلبًا من نوع POST إلى المسار، والذي يرتبط بالحدث create التابع للمتحكّم ArticlesController. بعد أن أنشأنا الاستمارة وعرّفنا المسار المرتبط به، أصبح باﻹمكان تعبئة حقول الاستمارة والضغط على زرّ اﻹرسال لبدء عملية إنشاء مقال جديد، ولكن عند إرسال المقال ستتلقّى الخطأ المتوقَّع التالي: علاج هذا الخطأ بسيط وهو إنشاء الحدث create ضمن المتحكّم ArticlesController. إنشاء المقالات سنقوم الآن بتعريف الحدث create ضمن صنف ArticlesController في الملف app/controllers/articles_controller.rb بعد الحدث new وكما يلي: class ArticlesController < ApplicationController def new end def create end end إن أعدت إرسال الاستمارة مرة أخرى فستلاحظ عدم حدوث أي تغيير في الصفحة. لا تقلق، هذا الأمر عائد إلى أنّ Rails يعيد الاستجابة “204 No Content” لأي حدث لا يحدّد الاستجابة المطلوبة. وقد أضفنا الحدث create دون تحديد الاستجابة المطلوبة منه، وهي في حالتنا هذه، إنشاء مقالة جديدة في قاعدة البيانات. عند إرسال الاستمارة يتم إرسال الحقول الخاصة بها إلى Rails على هيئة معاملات parameters، يمكن الإشارة إليها في الأحداث التابعة للمتحكّم وذلك لإنجاز مهّمة ما، ولتعرف كيف تبدو هذه المعاملات عدّل حدث create بالصورة التالية: def create render plain: params[:article].inspect end يأخذ التابع render هنا جدول تقطيع Hash بسيط مع المفتاح :plain والقيمة هي تابع params [:article].inspect. توابع params هي الكائن الذي يمثّل المعامل (أو الحقل) المأخوذ من الاستمارة. ويعيد تابع params كائن من نوع ActionController::Parameters والذي يتيح لنا الوصول إلى مفاتيح جدول التقطيع من خلال السلاسل النصّيّة Strings أو الرموز Symbols. وفي حالتنا هذه، فإن المعاملات المهمّة هي المعاملات المأخوذة من الاستمارة. لتوضيح عمل توابع params، إليك المثال التالي: في عنوان URL هذا: http://www.example.com/?username=dhh&email=dhh@mail.com فإن params[:username] تحمل القيمة “dhh” و params[:email] تحمل القيمة “dhh@mail.com”. والآن أعد إرسال الاستمارة مرة أخرى وستشاهد شيئًا مماثلًا لما يلي: <ActionController::Parameters {"title"=>"First Article!", "text"=>"This is my first article."} permitted: false> يعرض هذا الحدث المعاملات الخاصة بالمقالة والمأخوذة من الاستمارة، ولكن ليس هذا ما نريده بالضبط، فنحن نشاهد المعاملات ولكنّها لا تقدّم أي فائدة تذكر في حالتها هذه. في الدرس القادم سنتعرّف على النماذج Models في إطار العمل Rails وسنستخدمها في إضافة مقالة جديدة إلى قاعدة البيانات التابعة للتطبيق. المصدر: توثيقات Ruby on Rails.
  6. رغم أنّ شركة مايكروسوفت كانت تعتمد بشكل كلّي على نماذج ويب ASP.NET Forms في تطوير تطبيقات الويب، إلّا أنّه وفي الأعوام القليلة الماضيّة بدا أنّ تركيز الشركة منصبًّا بشكل واضح على تطوير تطبيقات الويب باستخدام ASP.NET MVC. وعلى الرغم مع عدم تخلّي عن تقنيّة Forms إلّا أنّ دورها على ما يبدو يتضاءل يومًا بعد يوم. طرحت مايكروسوفت هذا الامتحان للمرّة الأولى عام 2012. وباعتبار أنّ مصدر هذه التقنيّة هو مايكروسوفت فلا غنى لأيّ مطوّر عن الحصول على هذا الامتحان والنجاح فيه كوثيقة لإثبات المعرفة والمقدرة أمّام أيّ شركة أو جهة يطمح بالعمل لديها. فالشركات التقنيّة عمومًا تفضّل أصحاب الشهادات المعتمدة من كبريات الشركات العالميّة في توظيف الكادر للعمل لديها. وفي الحقيقة أنّه حتى بالنسبة للموظّفين الحاليين فإنّهم يفضّلون الحصول على مثل هكذا شهادات لتحسين وضعهم الحالي في شركاتهم. نبذة عن الامتحان يقيس هذا الامتحان مهاراتك كمطوّر ويب في استخدام هذه التقنيّة الرائعة بشكل صحيح وسليم. حيث أنّ هناك خمسة مجالات رئيسيّة يغطيها الامتحان. تنصح مايكروسوفت أن يتقدّم للامتحان كلّ مطوّر له خبرة برمجيّة عمرها خمسة سنوات أو ثلاثة أعوام في مجال الأعمال باستخدام هذه التقنيّة. يكلّف الامتحان حاليًّا مبلغًا قدره 150 دولارًا أمريكيًّا ويمكنك أن تحجز لإجراء هذا الامتحان عن طريق الإنترنت وذلك في أيّ مركز معتمد من مايكروسوفت. يمكنك مراجعة الصفحة الرسميّة للامتحان. يجري الامتحان ضمن المركز المعتمد في توقيت مُحدّد تلتزم به. تكون القاعة التي سيجري فيها الامتحان مراقبة، وبعد أن يقوم الموظّف المختص بتحميل أسئلة الامتحان على الحاسوب يبدأ التوقيت. من الضروري التنبّه إلى أنّ النقاط الواردة في هذا المقال لا تمثّل بالضرورة المصدر الوحيد لأسئلة الامتحان، ويجب الانتباه أيضًا إلى وجود بعض المواقع التي تزوّدك بأسئلة مسرّبة لامتحانات سابقة مع الحلول لهذه الأسئلة، وفي الغالب تكون مدفوعة وليست مجّانيّة. المشكلة هنا (بصرف النظر عن كونها مسألة غير قانونيّة) في أنّه قد تكون هذه الأسئلة غير صحيحة بمعنى أنّ مصدرها ليس امتحانات مايكروسوفت، وهناك احتمال أن يكون مصدرها امتحانات مايكروسوفت بالفعل ولكن قد تكون الإجابات المقترحة لها خاطئة، وفي جميع الأحوال لا تستطيع أن تضمن أن تتكرّر هذه الأسئلة في امتحانات قادمة. ومن الجدير ذكره أنّ هذا الامتحان يدخل ضمن متطلّبات الحصول على عدّة شهادات تمنحها مايكروسوفت أيضًا (تتطلّب كلّ شهادة عادةً النجاح في أكثر من امتحان)، فهو يدخل مثلًا ضمن شهادة مايكروسوفت في تطوير تطبيقات شير بوينت MCSD: SharePoint Applications. وشهادة مايكروسوفت في تطوير تطبيقات ويب MCSD: Web Applications ويجب ملاحظة أنّه اعتبارًا من 30 أبريل (نيسان) عام 2014 أصبحت أسئلة الامتحان تغطّي Visual Studio 2013 مع MVC5 بالإضافة إلى التحديثات الخاصة بـ Microsoft Azure. على ماذا سأحصل بعد النجاح في الامتحان؟ بعد النجاح في الامتحان ستحصل على وثيقة نجاح موقّعة من المدير التنفيذي لمايكروسوفت تحمل اسمك، واسم الامتحان الذي اجتزته بدون ذكر المعدّل الّذي حصلت عليه. وهناك شكلان لهذه الوثيقة: إلكترونيّ مجّاني، ومطبوع غير مجّاني. يمكنك تحميل النسخة الإلكترونيّة من موقع يتبع مايكروسوفت مخصّص لهذا الغرض، كما يمكنك طلب النسخة المطبوعة من هذه الشهادة لتصلك بالبريد لقاء رسمٍ رمزيّ. الملفت في الموضوع أنّ مايكروسوفت تسمح لك بمشاركة النسخة الإلكترونيّة مع أيّ جهة عن طريق رابط مخصّص لهذا الغرض، مما يسمح لك بإثبات امتلاكك لهذه الوثيقة بيسر وموثوقيّة عاليّة. فعلى سبيل المثال لا الحصر، يتطلّب موقع upwork.com الشهير للعمل المستقل مثل هذا الإثبات، في حال صرّحت حول امتلاكك لمثل هذه الشهادات. المجالات الرئيسيّة لأسئلة الامتحان فيما يلي المجالات الرئيسيّة للامتحان، والنسبة المئويّة لمساهمة كلّ منها في أسئلة الامتحان: تصميم بنية التطبيق (من 15% إلى 20%) تصميم واجهة المستخدم (من 20% إلى 25%) تطوير تجربة المستخدم (من 15% إلى 20%) اصطياد الأخطاء وتنقيح تطبيقات الويب (من 20% إلى 25%) تصميم وتطبيق النواحي الأمنيّة (من 20% إلى 25%) 1. تصميم بنية التطبيق ستحتاج في هذا المجال إلى معرفة كيفيّة التخطيط لطبقات layers التطبيق وذلك عن طريق التخطيط لفصل الأجزاء الرئيسيّة concerns main والاستخدام المناسب للنماذج models والمشاهد views والمتحكّمات controllers. والاختيار بين المعالجة من طرف العميل client-side أو من طرف الخادم server-side، والتخطيط من أجل قابليّة التوسّع scalability. كما ستحتاج لمعرفة كيفيّة تصميم تطبيق موزّع distributed application، وما يتضمّن ذلك من تصميم تطبيقات هجينة hybrid applications، والتخطيط والتنفيذ لدورة حياة تطبيق سحابيّ على Azure، وإعداد إدارة الحالة state management، وتصميم استراتيجيّة خاصّة باستخدام الذاكرة المؤقّتة cache والـ WebSockets، وتصميم وحدات (HTTP (HTTP Modules ومعالجات (HTTP (HTTP Handlers. 2. تصميم واجهة المستخدم يتطلّب هذا المجال تصميم واجهة مستخدم UI على تطبيق ويب ودراسة سلوكها، واستجابة التطبيق للمزايا الخاصّة بكلّ متصفّح عن طريق ميّزة تحديد نوع المتصفّح، والتخطيط لإنشاء تصميم متجاوب responsive design. 3. تطوير تجربة المستخدم في هذا المجال يجب على المتقدّم أن يكون ملمًّا بكيفيّة التخطيط لقابليّة الوصول والأمثَلَة لمحرّكات البحث SEO، والتخطيط لتوطين (ترجمة وما إلى ذلك) التّطبيق localization، وتصميم وتطبيق المتحكّمات controllers وطرائق action ضمن تطبيق MVC، وتصميم وتطبيق المسالك routes، والتحكّم بسلوك التطبيق باستخدام نقاط التوسعة extensibility points الخاصّة بـ MVC، والتقليل من عرض الحزمة المستخدم عن طريق ميزّتي التحزيم bundle والتصغير minify واستخدام شبكات توصيل المحتوى CDN. 4. اصطياد الأخطاء وتنقيح تطبيقات الويب بالنسبة إلى هذا المجال، يتوجّب معرفة كيفيّة منع الأخطاء أثناء التشغيل واصطيادها، وتصميم استراتيجيّة متكاملة لمعالجة الاستثناءات exception handling، وإجراء اختبارات ممنهجة لتطبيق ويب عن طريق إنشاء وتشغيل وحدات الاختبار unit tests وإنشاء كائنات اختبار زائفة mocks، وتنقيح تطبيق الويب ضمن عدّة متصفّحات، واستخدام محاكيات الأجهزة المحمولة mobile emulators، وتنقيح تطبيق Azure عن طريق جمع معلومات تشخيصيّة باستخدام الواجهة السحابيّة لأدوات تنقيح (Azure (Azure Diagnostics API، وغيرها من التقنيّات التي تتيحها Windows Azure لتنقيح الأخطاء. 5. تصميم وتطبيق النواحي الأمنية ستحتاج إلى معرفة كيفيّة إعداد وضبط عمليّة الاستيثاق authentication للمستخدمين، والاختيار بين الاستيثاق باستخدام ويندوز أو النماذج Forms أو الاستيثاق المخصّص، وضبط وإعداد التخويل authorization للمستخدمين بواسطة الأدوار roles، وإنشاء مزوّد أدوار مخصّص custom membership provider، وتصميم وتطبيق التوثيق باستخدام claims وذلك عبر مستودعات federated identity stores، وإدارة سلامة البيانات data integrity، وإنشاء موقع محميّ باستخدام ASP.NET وذلك بتطبيق شهادات SSL، وتشفير كلمات المرور باستخدام الحماية الإضافيّة salt password قبل تخزينها في قاعدة البيانات، وترميز المحتوى في HTML لمنع هجمات cross-site، ومنع هجمات حقن (SQL (SQL Injection بتمرير الوسائط إلى الاستعلام بشكل كائنيّ وليس بشكل نصّي مباشر، ومنع الهجمات من النوع XSRF.
  7. هذا الدّرس هو الجزء الثّاني من سلسلة من 6 دروس حول "نظرة عامة على إنشاء تطبيقات موجهة لبيئة الإنتاج". إذا لم تقرأ الدّرس الأول فألق نظرة عليه قبل أن تواصل القراءة. سنعدّ في هذا الجزء من السّلسلة تطبيق PHP الذي اخترناه مثالا (ووردبريس) إضافة إلى خادوم أسماء نطاقات DNS خاص. سيستعمل مستخدمو التطبيق اسمَ النطاق للوصول إليه؛ عبر العنوان https://www.example.com على سبيل المثال. يحيل العنوان إلى موزع الحِمل الذي سيعمل وسيطا عكسيا Reverse proxy لخواديم التطبيق التي تتصل بدورها بخادوم قاعدة البيانات. يمكِّننا استخدامُ نظام أسماء نطاقات خاصة Private DNS من الإشارة إلى عناوين الخواديم ضمن الشبكة الداخلية بأسماء المستضيفات الخاصة بها مما يسهل من عملية إعداد الخواديم. سنعد العناصر للتوّ التي أشرنا إليها على ستة خواديم، طبقا للترتيب التالي: نظام أسماء نطاقات خاصة (المستضيفان ns1 وns2).خادوم قاعدة البيانات (db1).خواديم التطبيق (app1 وapp2).موزع حمل (lb1). فلنبدأ بإعداد النطاقات. خواديم النطاقات الداخليةيساعد استخدام أسماء نطاقات بدلا من عناوين IP في التعرف على الخواديم التي نعمل عليها، كما أنه ضروري حال إدارة الكثير من الخواديم؛ إذ يمكّن من إحلال خادوم مكان آخر بمجرد تحديث سجلات النطاق (ضمن ملف وحيد) بدلا من من تحديث عناوين IP ضمن الكثير من ملفات الإعداد. سنعدّ نظام نطاقات للإحالة إلى عناوين الشبكة الداخلية التي توجد بها الخواديم بدلا من عناوين IP. سنشير إلى كل عنوان في الشبكة الداخلية بمستضيف ضمن النطاق الفرعي nyc3.example.com. سيكون عنوان خادوم قاعدة البيانات ضمن الشبكة الداخلية - على سبيل المثال - db1.nyc3.example.com؛ وهو ما ستترجمه خواديم النطاقات إلى عنوان IP داخلي (خاص). تنبغي الإشارة إلى أن اختيار اسم النطاق الفرعي nyc3.example.com اعتباطي. في العادة يُستخدم اسم الموقع الجغرافي للنطاق الفرعي؛ في مثالنا، تشير nyc3 إلى أن الخواديم تتواجد في مركز البيانات NYC3، وexample.com إلى اسم النطاق الخاص بالتطبيق. ستحصل على خادومي BIND هما ns1 وns2. أضف عناوين IP الخاصة بجميع الخواديم التي تخطط لإعدادها إن كنت تعرفها سلفًا، وإلا أضف سجلات النطاق بالتزامن مع إنشاء الخواديم. ننتقل لإعداد خادوم قاعدة البيانات. إعداد خادوم قاعدة البياناتنريد - طبقا للخطة - توزيع الحمل بين خواديم التطبيقات؛ أي تلك التي تشغِّل PHP وApache، لذا سنفْصِل قاعدة البيانات عن خواديم التطبيق لجعلها على خادوم خاص بها. من المهم جدا فصل قاعدة البيانات عن التطبيق في حال أردنا إمكانية التوسع أفقيا Horizontally Scaling (إضافة خواديم جديدة لتعمل مع تلك الموجودة) في تطبيقات PHP. تغطي هذه الفقرة كل الخطوات الضرورية لإعداد خادوم قاعدة البيانات، لكن يمكنك معرفة المزيد عن إعداد قاعدة بيانات MySQL بعيدة بقراءة مقال كيفية إعداد قاعدة بيانات بعيدة لتحسين أداء موقع يستخدِم MySQL. تثبيت MySQLنفذ الأمرين التاليين على خادوم قاعدة البيانات (db1) لتثبيت خادوم MySQL: sudo apt-get update sudo apt-get -y install mysql-serverأدخل كلمة السر التي تريد استخدامها للحساب الإداري في MySQL عندما يُطلب منك ذلك. نفذ: sudo mysql_install_db sudo mysql_secure_installationستحتاج لإدخال كلمة سر المستخدِم الإداري التي اخترتها عند تثبيت خادوم MySQL؛ بعدها سيسألك إن كنت تريد تغيير كلمة السر هذه، اضغط زر N إذا كنت لا تريد تغييرها. بالنسبة لبقية الأسئلة اضغط زر Enter لتأكيد الاختيارات الافتراضية. إعداد MySQL لاستخدام واجهة الشبكة الداخليةافتح ملف إعداد MySQL عبر الأمر التالي: sudo nano /etc/mysql/my.cnfابحث عن bind-address وحدد قيمة المتغير بعنوان IP قاعدة البيانات ضمن الشبكة الداخلية: bind-address = db1.nyc3.example.comاحفظ الملف ثم أغلقه. أعد تشغيل MySQL: sudo service mysql restartضبط قاعدة البيانات ومستخدميهانحتاج الآن لإنشاء قاعدة بيانات والمستخدمين الذين ستتصل خواديم التطبيقات عن طريقهم إلى قاعدة البيانات. استخدم الأمر التالي للدخول إلى سطر أوامر MySQL: mysql -u root -pأدخل كلمة السر عندما تُطلب. أنشئ قاعدة بيانات بتنفيذ الأمر التالي في سطر أوامر MySQL: CREATE DATABASE app;يرفق خادوم MySQL كل مستخدم بالخواديم التي يمكنه منها الاتصال بقاعدة بيانات. يوجد في مثالنا خادوما تطبيق يتصلان بقاعدة البيانات؛ لذا سننشئ مستخدما لكل واحد منهما. أنشئ مستخدما في قاعدة البيانات باسم appuser يمكنه الاتصال من العناوين الداخلية لخواديم التطبيقات (أي app1 وapp2). يجب استخدام نفس كلمة السر للمستخدمَيْن (اختر كلمة سر واكتبها مكان password في الأمرين أدناه): CREATE USER 'appuser'@'app1.nyc3.example.com' IDENTIFIED BY 'password'; CREATE USER 'appuser'@'app2.nyc3.example.com' IDENTIFIED BY 'password';سنضبط في ما بعد امتيازات المستخدم appuser، نكتفي الآن بإعطائه تحكما كاملا على قاعدة البيانات app: GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'app1.nyc3.example.com'; GRANT ALL PRIVILEGES ON app.* TO 'appuser'@'app2.nyc3.example.com'; FLUSH PRIVILEGES;تضمن الامتيازات الممتدة أن سكربت تثبيت التطبيق سيتمكن من تثبيته على قاعدة البيانات. إن كان لديك أكثر من خادومي تطبيقات، فيجب أن تنشئ حسابات المستخدمين الآن بنفس الكيفية. للخروج من سطر أوامر MySQL: exitاكتمل الآن إعداد خادوم قاعدة البيانات. ننتقل لإعداد خواديم التطبيقات. إعداد خواديم التطبيقاتتتصل خواديم التطبيق بخادوم قاعدة البيانات. اخترنا ووردبريس للتمثيل في هذا الدليل، وهو تطبيق PHP يعمل على خادوم ويب مثل Apache أو Nginx. سنضبط خادومين متطابقين لتوزيع الحِمل بينهما. تغطّي هذه الفقرة الخطوات الضرورية لإعداد خواديم التطبيق، لكن الموضوع مشروح بتفاصيل أكثر في مقال كيفية إعداد قاعدة بيانات بعيدة لتحسين أداء موقع يستخدِم MySQL انطلاقا من فقرة إعداد خادوم الويب. تثبيت Apache وPHPنفذ الأوامر التالية على كل واحد من الخادومين app1وapp2 لتثبيت Apache وPHP: sudo apt-get update sudo apt-get -y install apache2 php5-mysql php5 libapache2-mod-php5 php5-mcryptإعداد Apacheسنستخدم HAProxy على خادوم موزع الحمل للتعامل مع الاتصال عبر SSL، مما يعني أننا لا نريد أن يتصل المستخدمون بخادوميْ التطبيقات مباشرة. سنربط Apache بعنوان الشبكة الداخلية الخاص بكل واحد من الخادومين. نفّذ الأمر التالي على كل من الخادومين، app1 وapp2: sudo nano /etc/apache2/ports.confابحث عن السطر الذي توجد فيه العبارة Listen 80 وأضف عنوان خادوم التطبيق الخاص إليها، على النحو التالي (أبدل private_IP بعنوان IP الخاص بك): Listen private_IP:80احفظ الملف ثم أغلقه. يجعل هذا الإعداد خادوم Apache يُنصت لعناوين الشبكة الداخلية فقط؛ ممايعني أنه لا يمكن الوصول إليه عبر عنوان IP العمومي أو اسم المستضيف. أعد تشغيل Apache لأخذ التغيير في الحسبان: sudo service apache2 restartلا يمكن - وفق الإعداد الحالي - الوصول مباشرة إلى خادوم Apache؛ إذ تقتصر الاتصالات التي يقبلها على تلك القادمة من الشبكة الداخلية. سنعدّ - بعد قليل - موزع الحمل لإرسال الطلبات إلى الخواديم. تنزيل التطبيق وإعدادهاخترنا في هذه السّلسلة ووردبريس مثالا للتطبيق. إن كنت تستخدم تطبيق PHP مغايرا فيجب عليك تنزيله وعمل الإعدادات اللازمة (معلومات الاتصال بقاعدة البيانات على سبيل المثال)؛ ثم انتقل إلى الفقرة الموالية. نزل أرشيف ووردبريس على خادوم التطبيق الأول، app1: cd ~ wget http://wordpress.org/latest.tar.gzفك ضغط الأرشيف واستخرج ملفات ووردبريس: tar xvf latest.tar.gzانتقل إلى مجلّد ووردبريس المُستخرَج: cd wordpressيحتاج ووردبريس إلى مجلّد لوضع الملفات التي يحملها فيه؛ فلننشئ هذا المجلّد (wp-content/uploads): ode>mkdir wp-content/uploadsسنستخدم ملف إعداد ووردبريس النموذجي قالبا للإعداد: cp wp-config-sample.php wp-config.phpافتح الملف الإعداد من أجل تحريره: nano wp-config.phpاضبط اتصال ووردبريس بقاعدة البيانات بتحرير المعلومات الميَّزة في الأسطر التالية: /** The name of the database for WordPress */ define('DB_NAME', 'app'); /** MySQL database username */ define('DB_USER', 'appuser'); /** MySQL database password */ define('DB_PASSWORD', 'password'); /** MySQL hostname */ define('DB_HOST', 'db1.nyc3.example..com');نضيف الأسطر التالية إلى ملف إعداد ووردبريس لإخباره بأنه خلف وسيط عكسي يستخدم SSL (موزع الحمل يستخدم TLS/SSL للتعميّة): define('FORCE_SSL_ADMIN', true); if ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https') $_SERVER['HTTPS']='on';احفظ الملف ثم أغلقه. تبقّى الآن نقلُ ملفات ووردبريس إلى مجلد يمكن لخادوم الويب الوصول إليه من أجل خدمة الزوار. نقل ملفات التطبيق إلى جذر المستند Document Rootنحتاج الآن، بعد إعداد التطبيق، لنقل ملفات ووردبريس إلى جذر المستند في Apache حيث يمكن لخادوم الويب الوصول إليها وتقديمها لزوار الموقع. جذر المستند الافتراضي في Apache هو المسار var/www/html/ وهو ما سنستخدمه في مثالنا. احذف أولا ملف index.html الافتراضي: sudo rm /var/www/html/index.htmlاستخدم أداة rsync لنسخ ملفات ووردبريس إلى المجلد var/www/html/ اجعل www-data (الحساب الذي يشتغل به خادوم ويب Apache) مالكَ هذا المجلّد: sudo rsync -avP ~/wordpress/ /var/www/html sudo chgrp -R www-data /var/www/html/*أصبح خادوم التطبيق الأول app1 جاهزا؛ سنعد الآن خادوم التطبيق الآخر. تكرار ملفات التطبيق على الخواديم الأخرىيتوجب إعداد آلية لتكرار الملفات الموجودة في جذر المستند لخادوم الويب على مختلف الخواديم المكوِّنة للتطبيق؛ من أجل إبقاء ملفات التطبيق متجانسة عبر الخواديم. في حالة ووردبريس فإن استخدام واجهة الويب لتحميل الملفات وتثبيت الإضافات سيجعلها موجودة فقط على الخادوم الذي عالج الطلب. إن لم تكرَّر الملفات على جميع الخواديم فسيرى بعض زوار الموقع صفحات بصور ناقصة وإضافات مكسورة. إن كنت تستخدم تطبيقا آخر غير ووردبريس لا يحفظ بياناته (الملفات المحمَّلة والإضافات المنزّلة مثلا) على خادوم التطبيق فيمكنك الاكتفاء بنقل الملفات إلى الخادوم يدويا مرة واحدة. في هذه الحالة استخدم أداة rsync لنقل ملفات التطبيق من الخادوم app1 إلى الخادوم app2. يمكن استخدام GlusterFS لإنشاء تجزئة قرص مكرَّرة من الملفات الضرورية. الطريقة مشروحة في فقرة مزامنة الملفات في تطبيقات الويب ضمن مقال كيف تستخدم HAProxy لتوزيع الحمل بين خواديم تطبيق ووردبريس. اتبع الخطوات (تجاوز فقرة إعداد ملفات المستضيف لأن خادوم النطاقات لدينا يتولى المهمة) ثم اضبُط تكرار الملفات بين app1 وapp2. بعد الانتهاء من إعداد تكرار الملفات بين الخواديم نكون على استعداد لتجهيز موزِّع الحمل. إعداد موزع الحملاخترنا HAProxy موزعا للحمل؛ وسيعمل وسيطا عكسيا لخواديم التطبيق. سيصل المستخدمون إلى التطبيق عبر عنوان شبيه بhttps://www.example.com بعد المرور بموزع الحمل. تشرح هذه الفقرة الخطوات الضرورية لإعداد خادوم موزِّع للحمل/ نسخ شهادة SSLنفذ الخطوات التالية على خادوم موزع الحمل، lb1. ضع شهادة SSL (أحد متطلبات الجزء الأول من السّلسلة) ومفتاح الشهادة، إضافة لأي شهادات من سلطة وسيطة ضمن ملف pem. واحد (نفترض أن شهادات SSL موجودة في المجلّد root/certs/): cd /root/certs cat www.example.com.crt CAintermediate.ca-bundle www.example.com.key > www.example.com.pemثم انسخ ملف pem إلى المجلّد etc/ssl/private/: sudo cp www.example.com.pem /etc/ssl/private/سيستخدم HAProxy هذا الملف لإنهاء SSL. تثبيت HAProxyنفذ الأوامر التالية على خادوم موزع الحمل، lb1: sudo add-apt-repository ppa:vbernat/haproxy-1.5 sudo apt-get update sudo apt-get -y install haproxyإعداد HAProxyنحتاج لضبط إعداداتٍ عامة في HAProxy إضافة لإنهاء SSL والنهايات الخلفية Backend والأمامية Frontend المناسبة لجعله يعمل مع خواديم التطبيق. افتح ملف إعداد HAProxy لتحريره: sudo nano /etc/haproxy/haproxy.cfgخيارات عامة في إعداد HAProxyأول ما يجب فعله هو تحديد قيمة معقولة للحد الأعلى لعدد الاتصالات maxconn. يحدد هذا المتغير عدد الاتصالات الأكبر التي يسمح بها HAProxy في نفس الوقت؛ وهو ما قد يؤثر على جودة الخدمة ويحول دون انهيار خادوم الويب عند محاولته الإجابة على الكثير من الطلبات. يجب أن تبحث وتجرب قيما عدة لإيجاد تلك المناسبة لبيئة عملك. أضف السطر التالي إلى ملف إعداد HAProxy (اخترنا القيمة 2048): maxconn 2048أضف السطر التالي لضبط الحجم الأكبر للذاكرة المؤقتة لتخزين مفاتيح التعمية: tune.ssl.default-dh-param 2048أضف السطرين التاليين ضمن مقطع defaults مباشرة بعد السطر الذي توجد به mode http: option forwardfor option http-server-closeتفعل الأسطر التالية إذا أضيفت ضمن مقطع defaults صفحة إحصاءات HAProxy (أبدل user وpassword بقيم آمنة): stats enable stats uri /stats stats realm Haproxy\ Statistics stats auth user:passwordيمكن بعد التفعيل عرض إحصاءات HAProxy بالذهاب إلى الصفحة التالية https://www.example.com/stats. لم ننته بعد من ملف إعدادات HAProxy، سنضبط في ما يلي إعدادات الوسيط. إعداد الوسيط في HAProxyنبدأ بإضافة نهاية أمامية للتعامل مع اتصالات HTTP الواردة. نضيف في نهاية ملف الإعداد نهاية أمامية باسم www-http عبر الأسطر التالية: frontend www-http bind www.example.com:80 reqadd X-Forwarded-Proto:\ http default_backend app-backendالهدف من هذا الإعداد هو قبول اتصالات HTTP من أجل توجيهها عبر اتصال HTTPS. ثم نضيف نهاية أمامية للتعامل مع اتصالات HTTPS، تأكد من تحديد ملف pem المناسب. frontend www-https bind www.example.com:443 ssl crt /etc/ssl/private/www.example.com.pem reqadd X-Forwarded-Proto:\ https default_backend app-backendنستكمل الإعداد بضبط النهاية الخلفية: backend app-backend redirect scheme https if !{ ssl_fc } server app1 app1.nyc3.example.com:80 check server app2 app2.nyc3.example.com:80 checkتحدد النهاية الخلفية خواديم التطبيقات التي يوزَّع بينها الحمل. يطلب السطر: redirect scheme https if !{ ssl_fc } توجيه اتصالات HTTP إلى HTTPS. احفظ ملف haproxy.cfg ثم أغلقه. HAProxy جاهز الآن لبدء العمل؛ لكن سنفعل أولا السجلات Logs. تفعيل سجلات HAProxyافتح ملف rsyslog للتحرير: sudo nano /etc/rsyslog.confابحث عن الأسطر التالية وانزع علامة التعليق من أجل تفعيل بروتوكول UDP عند استقبال سجلات النظام Syslog. تبدو الأسطر كما يلي بعد نزع علامة التعليق: $ModLoad imudp $UDPServerRun 514 $UDPServerAddress 127.0.0.1أعد تشغيل خدمة rsyslog لتفعيل الإعداد الجديد: sudo service rsyslog restartسجل HAProxy مفعَّل الآن وسيُنشأ ملف var/log/haproxy.log/ فور بدء عمل HAProxy. إعادة تشغيل HAProxyأعد تشغيل HAProxy لأخذ التعديلات في الحسبان. sudo service haproxy restartاكتمل الآن إعداد موزع الحِمل، ننتقل لتثبيت التطبيق (ووردبريس). تثبيت ووردبريسسيتوجب علينا - قبل البدء في استخدام ووردبريس - تشغيل سكربت التثبيت الذي يهيئ قاعدة البيانات ليستخدمها ووردبريس. أدخل إلى العنوان التالي في المتصفح: https://www.example.com/wp-admin/install.phpستظهر شاشة تثبيت ووردبريس. املأء الحقول بما يناسب ثم انقر على زر التثبيت. بعد انتهاء تثبيت ووردبريس يصبح التطبيق جاهزا للعمل. خاتمةاكتمل الآن إعداد الخواديم المكوِّنة للتطبيق، وهذا الأخير جاهز للاستخدام. يمكنك الدخول بحساب المدير كما يمكن لزوار موقعك الوصول إليه عبر HTTPS عند استخدام اسم النطاق المناسب. تأكد قبل الانتقال إلى الجزء الموالي من الدليل أن التطبيق يعمل بطريقة صحيحة. ترجمة -وبتصرّف- لمقال Building for Production: Web Applications — Deploying لصاحبه Mitchell Anicas. حقوق الصورة البارزة: Designed by Freepik.