تعرّفنا في الدرس السابق على طريقة تثبيت إطار العمل 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 على المقالات الموجودة في تطبيقنا.
اقتباستضمّ لغة Ruby توابع من نوع
public
وprivate
وprotected
ولكن الأحداث هي توابع من نوعpublic
حصرًا.
إن أعدت تحميل الصفحة ستتلقّى خطأً جديدًا:
يشير هذا الخطأ إلى عدم قدرة Rails على إيجاد الحدث new
ضمن المتحكّم ArticlesController
الذي قمنا بإنشائه للتوّ. وهذا عائد إلى أنّ المتحكّمات تكون فارغة عند إنشائها إلا إذا حدّدنا الأحداث المطلوبة خلال عملية إنشاء المتحكّم.
ولتعريف حدث جديد بصورة يدوية، سنحتاج فقط إلى تعريف تابع جديد ضمن المتحكم. افتح الملف app/controllers/articles_controller.rb
وضمن الصنف ArticlesController
عرّف تابعًا جديدًا وكما يلي:
class ArticlesController < ApplicationController
def new
end
end
والآن أعد تحميل الصفحة في المتصفّح وستتلقّى خطأً آخر:
يظهر هذا الخطأ لأنّ Rails يتوقّع أنه يجب أن تمتلك الأحداث الصرفة المشابهة لهذا الحدث عروضًا ترتبط معها لعرض المعلومات التي تتضمنها، ونظرًا لعدم وجود أي عرض مرتبط بهذا الحدث، أطلق Rails هذا الخطأ.
لنطّلع على رسالة الخطأ الكاملة:
اقتباسArticlesController#new is missing a template for this request format and variant. request.formats: [“text/html”] request.variant: [] NOTE! For XHR/Ajax or API requests, this action would normally respond with 204 No Content: an empty white screen. Since you’re loading it in a web browser, we assume that you expected to actually render a template, not… nothing, so we’re showing an error to be extra-clear. If you expect 204 No Content, carry on. That’s what you’ll get from an XHR or API request. Give it a shot.
لنستعرض النص السابق سريعًا، ونفهم مضمونه بصورة جيدة.
يحدّد الجزء الأول من نصّ الخطأ القالب المفقود، وفي هذه الحالة القالب المفقود هو 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 وسنستخدمها في إضافة مقالة جديدة إلى قاعدة البيانات التابعة للتطبيق.
أفضل التعليقات
لا توجد أية تعليقات بعد
انضم إلى النقاش
يمكنك أن تنشر الآن وتسجل لاحقًا. إذا كان لديك حساب، فسجل الدخول الآن لتنشر باسم حسابك.