Rails/routing

من موسوعة حسوب
مراجعة 06:14، 7 يناير 2019 بواسطة جميل-بيلوني (نقاش | مساهمات) (إنشاء الصفحة؛ هذه الصفحة من مساهمات دعاء فرح)
(فرق) → مراجعة أقدم | المراجعة الحالية (فرق) | مراجعة أحدث ← (فرق)

يغطي هذا الدليل الميزات التي يواجهها المستخدم في عمليات التوجيه في Rails.

بعد قراءة هذا الدليل، ستعرف:

  • كيفية تفسير الشيفرة في config/routes.rb.
  • كيفية بناء المسارات الخاصة بك باستخدام إما أسلوب الحيلة (resourceful style) المفضل أو طريقة المطابقة (match method).
  • كيفية الإعلان عن معاملات المسار الموجه، والتي تمرر إلى إجراءات وحدة التحكم (controller actions).
  • كيفية إنشاء المسارات وعناوين URL تلقائيًا باستخدام مساعدي المسار الموجه.
  • التقنيات المتقدمة مثل إنشاء قيود وتثبيت نقاط نهاية Rack.

الغرض من توجيه المسارات في Rails

يتعرف جهاز التوجيه في Rails على عناوين URL ويرسلها إلى إجراء وحدة التحكم، أو إلى تطبيق Rack. ويمكنه أيضًا إنشاء مسارات وعناوين URL، مع تجنب الحاجة إلى استخدام رموز ثابتة في الواجهة الخاصة بك.

توصيل عناوين URL بالشيفرة

عندما يتلقى تطبيق Rails طلبًا واردًا لما يلي: GET /patients/17  

يطلب من جهاز التوجيه مطابقته مع إجراء وحدة تحكم. إذا كان أول مسار مطابق هو:

get '/patients/:id', to: 'patients#show'

يرسل الطلب إلى وحدة التحكم patients الإجراء show مع { id: '17' } في params.

إنشاء مسارات وعناوين URL من الشيفرة

يمكنك أيضًا إنشاء مسارات وعناوين URL. إذا تم تعديل المسار الموجه أعلاه ليكون:

get '/patients/:id', to: 'patients#show', as: 'patient'

ويحتوي التطبيق الخاص بك على هذا الرمز في وحدة التحكم:

@patient = Patient.find(params[:id])

وهذا في الواجهة يقابل:

<%= link_to 'Patient Record', patient_path(@patient) %>

ثم ينشئ جهاز التوجيه المسار /patients/17. هذا يقلل من هشاشة الواجهة الخاص بك ويجعل التعليمات البرمجية الخاصة بك أسهل للفهم. لاحظ أن الهوية id لا تحتاج إلى التحديد في مساعد المسار الموجه.

تهيئة جهاز توجيه المسارات في Rails

توجد المسارات الموجهة للتطبيق أو المحرك (engine) في الملف config/routes.rb وعادةً ما تبدو كالتالي:

Rails.application.routes.draw do

 resources :brands, only: [:index, :show] do

   resources :products, only: [:index, :show]

 end

 resource :basket, only: [:show, :update, :destroy]

 resolve("Basket") { route_for(:basket) }

End

نظرًا لأن هذا ملف مصدر روبي منتظم، يمكنك استخدام جميع ميزاته لمساعدتك في تحديد مساراتك الموجهة، لكن كن حذرًا مع أسماء المتغيرات، إذ إنها يمكن أن تتعارض مع توابع DSL الخاصة بالموجه.

ملاحظة: تقوم كتلة Rails.application.routes.draw do… end التي تلتزم بتعريفات المسار الموجه الخاصة بك بإنشاء النطاق الخاص بجهاز التوجيه DSL ويجب عدم حذفه.

توجيه المورد: الافتراضي في Rails

يتيح لك توجيه الموارد إمكانية الإعلان بسرعة عن جميع المسارات الشائعة لوحدة التحكم كثيرة الموارد. بدلًا من الإعلان عن مسارات موجهة منفصلة للإجراءات index، و show، و new، و edit، و create، و update و destroy الخاصة بك، فإن المسار كثير المورد يعلن عنه في سطر واحد من الشيفرة.

الموارد على الويب

تطلب صفحات المتصفحات من Rails عن طريق تقديم طلب لعنوان URL باستخدام تابع HTTP محدد، مثل GET و POST و PATCH و PUT و DELETE. كل تابع هو طلب لتنفيذ عملية على المورد. يحدد مسار المورد الموجه عددًا من الطلبات ذات الصلة بالإجراءات في وحدة التحكم الواحدة.

عندما يتلقى تطبيق Rails طلبًا واردًا لما يلي:

DELETE /photos/17

يطلب من جهاز التوجيه لتعيينه إلى إجراء وحدة تحكم. إذا كان أول مسار مطابق هو:

resources :photos

سترسل Rails ذلك الطلب للإجراء destroy على وحدة التحكم photos مع {id: '17'} في params.

CRUD والأفعال والإجراءات

في Rails، يوفر المسار كثير المورد تخطيطًا بين أفعال HTTP وعناوين URL لإجراءات التحكم. من خلال الاتفاقية، كل إجراء يخطط أيضًا لعملية CRUD محددة في قاعدة البيانات. إدخال فردي في ملف التوجيه يكون مثل:

resources :photos

ينشئ سبعة مسارات مختلفة في التطبيق الخاص بك معيَّنةً جميعها إلى وحدة تحكم Photos:

فعل HTTP المسار وحدة التحكم # الإجراء الإستخدامات
GET ‎/photos photos#index عرض قائمة بجميع الصور.
GET ‎/photos/new photos#new إرجاع نموذج HTML لإنشاء صورة جديدة.
POST ‎/photos photos#create خلق صورة جديدة.
GET ‎/photos/:id photos#show عرض صورة محددة.
GET ‎/photos/:id/edit photos#edit إرجاع نموذج HTML لتحرير صورة.
PATCH/PUT ‎/photos/:id photos#update تحديث صورة معينة.
DELETE ‎/photos/:id photos#destroy حذف صورة معينة.

ملاحظة: نظرًا لأن جهاز التوجيه يستخدم الفعل HTTP وعنوان URL لمطابقة الطلبات الواردة، فإن أربعة عناوين URL تتحول إلى سبعة إجراءات مختلفة.

ملاحظة: تُطابَق مسارات Rails بالترتيب المحدد لها، لذلك إذا كانت لديك resources :photos الموجودة أعلى get photos/poll، فسيطابق مسار الإجراء show السطر resources قبل سطر get. لحل هذه المشكلة، قم بتحريك سطر get فوق سطر resources بحيث يطابقه أولًا.

المسار ومساعد URL

سيؤدي إنشاء مسار موجه كثير المورد إلى كشف عدد من المساعدين إلى وحدات التحكم في تطبيقك. في حالة resources :photos:

  • photos_path returns /photos
  • new_photo_path returns /photos/new
  • edit_photo_path(:id) returns /photos/:id/edit (for instance, edit_photo_path(10) returns /photos/10/edit)
  • photo_path(:id) returns /photos/:id (for instance, photo_path(10) returns /photos/10)

كل من هؤلاء المساعدين لديه مساعد ‎_url مقابل (مثل photos_url) الذي يعيد نفس المسار مسبوقًا ببادئة المضيف والمنفذ والمسار الحالي.

تحديد موارد متعددة في نفس الوقت

إذا كنت بحاجة إلى إنشاء مسارات توجيه لأكثر من مورد واحد، فيمكنك توفير جزء من الكتابة عن طريق تعريفهم جميعًا باستدعاءٍ واحدٍ إلى resources:

resources :photos, :books, :videos

هذا يعمل بالضبط بطريقة مشابهة للشيفرة التالية:

resources :photos

resources :books

resources :videos

الموارد الفردية

في بعض الأحيان، يكون لديك مورد يبحث عنه العملاء دائمًا دون الإشارة إلى معرف ID. على سبيل المثال، ترغب في أن يعرض ‎/profile دائمًا ملف تعريف المستخدم الذي قام بتسجيل الدخول حاليًا. في هذه الحالة، يمكنك استخدام مورد مفرد لتعيين ‎/profile (بدلًا من ‎/profile/:id) إلى الإجراء show:

get 'profile', to: 'users#show'

تمرير سلسلة نصية (String) إلى to:‎ ستتوقع أن تكون بالتنسيق controller#action. عند استخدام رمز (Symbol)، يجب استبدال الخيار to:‎ بالقيمة action:‎. عند استخدام سلسلة نصية دون الرمز #، يجب استبدال الخيار to:‎ بـ controller:‎ بالشكل التالي:

get 'profile', action: :show, controller: 'users'

هذا مسار موجه كثير المورد:

resource :geocoder

resolve('Geocoder') { [:geocoder] }

يخلق ستة مسارات موجهة مختلفة في التطبيق الخاص بك كلها معيَّنة إلى وحدة تحكم Geocoders:

فعل HTTP المسار وحدة التحكم # الإجراء الإستخدامات
GET ‎/geocoder/new geocoders#new إرجاع نموذج HTML لإنشاء geocoder.
POST ‎/geocoder geocoders#create إنشاء geocoder جديد.
GET ‎/geocoder geocoders#show عرض مورد geocoder واحد و فقط.
GET ‎/geocoder/edit geocoders#edit إرجاع نموذج HTML لتحرير geocoder.
PATCH/PUT ‎/geocoder geocoders#update تحديث مورد geocoder واحد و فقط.
DELETE ‎/geocoder geocoders#destroy حذف مورد geocoder.

ملاحظة: نظرًا لأنك قد ترغب في استخدام وحدة التحكم نفسها لمسار فريد (‎/account) ومسار الجمع (‎/accounts/45)، فإن الموارد الفردية ستخضع إلى وحدات تحكم الجمع. على سبيل المثال، المورد ‎:photo والموارد ‎:photos تنشئ مسارات توجيه مفرد ومجتمعة تعين لنفس وحدة التحكم (PhotosController).

يولّد المسار الموجه كثير المورد المفرد (singular resourceful route) هؤلاء المساعدين:

  • new_geocoder_path returns /geocoder/new
  • edit_geocoder_path returns /geocoder/edit
  • geocoder_path returns /geocoder

كما هو الحال مع موارد الجمع، فإن نفس المساعدين الذين ينتهون في ‎_url سيتضمنون أيضًا بادئة المضيف والمنفذ والمسار.

وحدة تحكم مجالات الأسماء والتوجيه

قد ترغب في تنظيم مجموعات من وحدات التحكم تحت مجال اسم (namespace). الأكثر شيوعًا، يمكنك تجميع عدد من وحدات التحكم الإدارية تحت مجال الاسم Admin::‎. يمكنك وضع وحدات التحكم هذه تحت دليل app/controllers/admin، ويمكنك تجميعها معًا في جهاز التوجيه:

namespace :admin do

 resources :articles, :comments

End

سيؤدي ذلك إلى إنشاء عدد من المسارات لكل من وحدة التحكم في articles و comments. من أجل Admin::ArticlesController، ستنشئ Rails:

فعل HTTP المسار وحدة التحكم # الإجراء مسمى المساعد
GET ‎/admin/articles admin/articles#index admin_articles_path
GET ‎/admin/articles/new admin/articles#new new_admin_article_path
POST ‎/admin/articles admin/articles#create admin_articles_path
GET ‎/admin/articles/:id admin/articles#show admin_article_path(:id)‎
GET ‎/admin/articles/:id/edit admin/articles#edit edit_admin_article_path(:id)‎
PATCH/PUT ‎/admin/articles/:id admin/articles#update admin_article_path(:id)‎
DELETE ‎/admin/articles/:id admin/articles#destroy admin_article_path(:id)‎
مسمى المساعد وحدة التحكم # الإجراء المسار فعل HTTP
admin_articles_path admin/articles#index /admin/articles GET
new_admin_article_path admin/articles#new /admin/articles/new GET
admin_articles_path admin/articles#create /admin/articles POST
admin_article_path(:id) admin/articles#show /admin/articles/:id GET
edit_admin_article_path(:id) admin/articles#edit /admin/articles/:id/edit GET
admin_article_path(:id) admin/articles#update /admin/articles/:id PATCH/PUT
admin_article_path(:id) admin/articles#destroy /admin/articles/:id DELETE

إذا كنت تريد توجيه ‎/articles (بدون البادئة ‎/admin) إلى Admin::ArticlesController، فيمكنك استخدام:

scope module: 'admin' do

 resources :articles, :comments

end

أو في حالة واحدة:

resources :articles, module: 'admin'

إذا كنت تريد توجيه ‎/admin/articles إلى ArticlesController (بدون بادئة الوحدة Admin::‎)، فيمكنك استخدام:

scope '/admin' do

 resources :articles, :comments

end

أو في حالة واحدة:

resources :articles, path: '/admin/articles'

في كل من هذه الحالات، تظل المسارات الموجهة المسماة كما هي إذا لم تستخدم النطاق (scope). في الحالة الأخيرة، تعيَّن المسارات التالية إلى ArticlesController:

فعل HTTP المسار وحدة التحكم # الإجراء مسمى المساعد
GET ‎/admin/articles articles#index articles_path
GET ‎/admin/articles/new articles#new new_article_path
POST ‎/admin/articles articles#create articles_path
GET ‎/admin/articles/:id articles#show article_path(:id)‎
GET ‎/admin/articles/:id/edit articles#edit edit_article_path(:id)‎
PATCH/PUT ‎/admin/articles/:id articles#update article_path(:id)‎
DELETE ‎/admin/articles/:id articles#destroy article_path(:id)‎

ملاحظة: إذا كنت بحاجة إلى استخدام مجال اسم وحدة تحكم (controller namespace) مختلف داخل كتلة مجال الاسم (namespace block)، فيمكنك تحديد مسار جهاز تحكم مطلق، مثل: get '/foo' => '/foo#index'‎.

الموارد المتداخلة

من الشائع أن يكون لديك موارد منطقية للفرع childern من الموارد الأخرى. على سبيل المثال، لنفترض أن تطبيقك يتضمن هذه النماذج:

class Magazine < ApplicationRecord

 has_many :ads

end

class Ad < ApplicationRecord

 belongs_to :magazine

End

تتيح لك المسارات المتداخلة التقاط هذه العلاقة في التوجيه الخاص بك. في هذه الحالة، يمكنك تضمين إعلان المسار هذا:

resources :magazines do

 resources :ads

end

بالإضافة إلى المسارات الموجهة للمجلات (magazines)، سيوجه هذا الإعلان أيضًا الإعلانات إلى AdsController. تتطلب عناوين URL للإعلان عن مجلة:

فعل HTTP المسار وحدة التحكم # الإجراء الاستخدامات
GET ‎/magazines/:magazine_id/ads ads#index عرض قائمة بجميع الإعلانات لمجلة محددة.
GET ‎/magazines/:magazine_id/ads/new ads#new إرجاع نموذج HTML لإنشاء إعلان جديد ينتمي إلى مجلة معينة.
POST ‎/magazines/:magazine_id/ads ads#create إنشاء إعلان جديد ينتمي إلى مجلة محددة.
GET ‎/magazines/:magazine_id/ads/:id ads#show عرض إعلان معين ينتمي إلى مجلة محددة.
GET ‎/magazines/:magazine_id/ads/:id/edit ads#edit إرجاع نموذج HTML لتحرير إعلان ينتمي إلى مجلة معينة.
PATCH/PUT ‎/magazines/:magazine_id/ads/:id ads#update تحديث إعلان معين ينتمي إلى مجلة محددة.
DELETE ‎/magazines/:magazine_id/ads/:id ads#destroy حذف إعلان معين ينتمي إلى مجلة محددة.

سيؤدي هذا أيضًا إلى إنشاء مساعدين للتوجيه مثل magazine_ads_url و edit_magazine_ad_path. يأخذ هؤلاء المساعدون نسخة للمجلة كأول معامل (magazine_ads_url(@magazine)‎).

حدود التداخل

يمكنك أن تشعِّب الموارد ضمن الموارد المتشعبة الأخرى إذا أردت ذلك. فمثلًا:

resources :publishers do

 resources :magazines do

   resources :photos

 end

End

تصبح الموارد المتداخلة بعمق بطيئة. في هذه الحالة مثلًا، سيتعرف التطبيق على مسارات مثل:

/publishers/1/magazines/2/photos/3

سيكون مساعد المسار المقابل هو publisher_magazine_photo_url، مما يتطلب منك تحديد كائنات على جميع المستويات الثلاثة. في الواقع، هذا الوضع مربكًا بما فيه الكفاية، إذ يقترح جيمس باك (Jamis Buck) في مقالة شائعة له قاعدةً أساسيةً لتصميم Rails بشكل جيد: " لا ينبغي أبدًا أن تتداخل الموارد أكثر من 1 مستوى عميق."

التداخل الضحل

تتمثل إحدى طرق تجنب التداخل العميق (كما هو موصى به أعلاه) في إنشاء إجراءات المجموعة المحددة ضمن الأصل parent، وذلك للحصول على إحساس بالتسلسل الهرمي hierarchy ولعدم تداخل إجراءات العضو. بعبارة أخرى، لإنشاء مسارات فقط مع الحد الأدنى من المعلومات لتحديد المورد بشكل فريد، مثل هذا:

resources :articles do

 resources :comments, only: [:index, :new, :create]

end

resources :comments, only: [:show, :edit, :update, :destroy]

تحقق هذه الفكرة توازنًا بين المسارات الوصفية والتداخل العميق. توجد صيغة مختصرة لتحقيق ذلك، عبر الخيار ‎:shallow:

resources :articles do

 resources :comments, shallow: true

end

سيؤدي ذلك إلى إنشاء نفس المسارات بالضبط مثل المثال الأول. يمكنك أيضًا تحديد الخيار ‎:shallow في المورد الرئيسي parent، وفي هذه الحالة ستكون جميع الموارد المتداخلة ضحلة:

resources :articles, shallow: true do

 resources :comments

 resources :quotes

 resources :drafts

end

التابع الضحل shallow الذي يخص DSL يخلق مجالًا داخليًا يكون كل تداخل فيه ضحلًا. هذا ينشئ نفس المسارات الموجهة مثل المثال السابق:

shallow do

 resources :articles do

   resources :comments

   resources :quotes

   resources :drafts

 end

end

هناك خياران للنطاق (scope) لتخصيص المسارات الموجهة الضحلة. البادئات ‎:shallow_path لمسارات العضو مع المعامل المحدد:

scope shallow_path: "sekret" do

 resources :articles do

   resources :comments, shallow: true

 end

end

يحتوي مورد التعليقات هنا على المسارات التالية التي أنشئت له:

فعل HTTP المسار وحدة التحكم# الإجراء مسمى المساعد
GET ‎/articles/:article_id/comments(.:format)‎ comments#index article_comments_path
POST ‎/articles/:article_id/comments(.:format)‎ comments#create article_comments_path
GET ‎/articles/:article_id/comments/new(.:format)‎ comments#new new_article_comment_path
GET ‎/sekret/comments/:id/edit(.:format)‎ comments#edit edit_comment_path
GET ‎/sekret/comments/:id(.:format)‎ comments#show comment_path
PATCH/PUT ‎/sekret/comments/:id(.:format)‎ comments#update comment_path
‎/sekret/comments/:id(.:format)‎ comments#destroy comment_path

الخيار ‎:shallow_prefix يضيف المعامل المحدد للمساعدين المسمايين:

scope shallow_prefix: "sekret" do

 resources :articles do

   resources :comments, shallow: true

 end

end

يحتوي مورد التعليقات هنا على المسارات الموجهة التالية التي أنشئت له:

فعل HTTP المسار وحدة التحكم# الإجراء مسمى المساعد
GET ‎/articles/:article_id/comments(.:format)‎ comments#index article_comments_path
POST ‎/articles/:article_id/comments(.:format)‎ comments#create article_comments_path
GET ‎/articles/:article_id/comments/new(.:format)‎ comments#new new_article_comment_path
GET ‎/comments/:id/edit(.:format)‎ comments#edit edit_sekret_comment_path
GET ‎/comments/:id(.:format)‎ comments#show sekret_comment_path
PATCH/PUT ‎/comments/:id(.:format)‎ comments#update sekret_comment_path
DELETE ‎/comments/:id(.:format)‎ comments#destroy sekret_comment_path

اهتمامات التوجيه

تسمح لك اهتمامات التوجيه (Routing concerns) بالإعلان عن المسارات الموجهة الشائعة التي يمكن إعادة استخدامها داخل الموارد والمسارات الأخرى. ألق نظرة على الشيفرة التالي لمعرفة كيفية تعريف اهتمام concern:

concern :commentable do

 resources :comments

end

concern :image_attachable do

 resources :images, only: :index

end

يمكن استخدام هذه الاهتمامات concern في الموارد لتجنب تكرار الرموز ومشاركة السلوك عبر المسارات:

resources :messages, concerns: :commentable

resources :articles, concerns: [:commentable, :image_attachable]

ما ورد أعلاه يعادل ما يلي:

resources :messages do

 resources :comments

end

resources :articles do

 resources :comments

 resources :images, only: :index

end

كما يمكنك استخدامها في أي مكان تريده داخل المسارات الموجهة، مثل في استدعاء نطاق (scope) أو مجال أسماء (namespace):

namespace :articles do

 concerns :commentable

end

إنشاء مسارات وعناوين URL من الكائنات

بالإضافة إلى استخدام مساعدين التوجيه، تستطيع Rails أيضًا إنشاء مسارات وعناوين URL من مصفوفة من المعاملات. على سبيل المثال، لنفترض أن لديك مجموعة المسارات الموجهة التالية:

resources :magazines do

 resources :ads

end

عند استخدام magazine_ad_path، يمكنك تمرير نسخ من Magazine و Ad بدلًا من المعرفات الرقمية IDs:

<%= link_to 'Ad details', magazine_ad_path(@magazine, @ad) %>

يمكنك أيضًا استخدام url_for مع مجموعة من الكائنات، وسوف تحدد Rails المسار الموجهة الذي تريده تلقائيًا:

<%= link_to 'Ad details', url_for([@magazine, @ad]) %>

في هذه الحالة، سترى Rails أن magazine@ هو Magazine و ad@ هو Ad وبالتالي ستستخدم المساعد magazine_ad_path. في المساعدين مثل link_to، يمكنك تحديد الكائن بدلًا من استدعاء url_for بالكامل:

<%= link_to 'Ad details', [@magazine, @ad] %>

إذا كنت تريد الارتباط بمجلة فقط:

<%= link_to 'Magazine details', @magazine %>

بالنسبة إلى الإجراءات الأخرى، تحتاج فقط إلى إدراج اسم الإجراء باعتباره العنصر الأول في المصفوفة:

<%= link_to 'Edit Ad', [:edit, @magazine, @ad] %>

يتيح لك ذلك التعامل مع نسخ النماذج الخاصة بك كعناوين URL، وهي ميزة أساسية لاستخدام النمط كثير المورد.

إضافة المزيد من الإجراءات RESTful

لا تقتصر على المسارات الموجهة السبعة التي ينشئها توجيه RESTful بشكل افتراضي. يمكنك إضافة مسارات موجهة إضافية، إذا كنت ترغب في ذلك، تنطبق على المجموعة أو على أعضاء فرديين في المجموعة.

إضافة مسارات الأعضاء

لإضافة مسار موجه عضو، ما عليك سوى إضافة الكتلة member إلى كتلة الموارد resource:

resources :photos do

 member do

   get 'preview'

 end

end

سيتعرف هذا على ‎/photos/1/preview مع GET، ويوجهه إلى الإجراء preview الذي يخص PhotosController، مع تمرير قيمة معرف المورد id في المعاملات [‎:id]. سيؤدي أيضًا إلى إنشاء photos_preview_url والمساعدين photo_preview_path.

ضمن كتلة مسارات الأعضاء الموجهة، كل اسم مسار (route name) يحدد فعل HTTP سيُتعرَّف عليه. يمكنك استخدام get أو patch أو put أو post أو delete هنا. إذا لم يكن لديك العديد من مسارات الأعضاء الموجهة، فيمكنك أيضًا تمرير ‎:on إلى المسار، وإلغاء الكتلة:

resources :photos do

 get 'preview', on: :member

end

يمكنك ترك الخيار ‎:on، إذ سيؤدي ذلك إلى إنشاء نفس مسار العضو باستثناء أن قيمة معرف المورد id ستكون متاحة في [params[:photo_id بدلًا من [params[:id.

إضافة مسارات التجميع

لإضافة مسار موجه إلى المجموعة:

resources :photos do

 collection do

   get 'search'

 end

end

سيؤدي هذا إلى تمكين Rails للتعرف على مسارات مثل ‎/photos/search باستخدام GET، والتوجيه إلى الإجراء search الذي يخص PhotosController. سيؤدي أيضًا إلى إنشاء مساعدي التوجيه search_photos_url و search_photos_path.

كما هو الحال مع توجيهات الأعضاء (member routes)، يمكنك تمرير ‎:on إلى توجيه بالشكل التالي:

resources :photos do

 get 'search', on: :collection

end

إضافة توجيهات لإجراءات جديدة إضافية

يمكن إضافة إجراء جديد بديل باستخدام الاختصار ‎:on بالشكل التالي:

resources :comments do

 get 'preview', on: :new

end

سيؤدي هذا إلى تمكين Rails للتعرف على مسارات مثل ‎/comments/new/preview باستخدام GET، وتوجيهها إلى الإجراء preview الذي يخص CommentController. سيؤدي أيضًا إلى إنشاء مساعدي التوجيه preview_new_comment_url و preview_new_comment_path.

فائدة: إذا وجدت نفسك تضيف العديد من الإجراءات الإضافية إلى مسار موجه ذي أهمية، فقد حان الوقت للتوقف وسؤال نفسك ما إذا كنت تموه عن وجود مورد آخر.

المسارات الموجهة غير كثيرة المورد (Non-Resourceful)

بالإضافة إلى توجيه الموارد، تتمتع Rails بدعم قوي لتوجيه عناوين URL العشوائية إلى الإجراءات. هنا، لا يمكنك الحصول على مجموعات من التوجيهات التي تنشأ تلقائيًا من خلال توجيه الموارد. بدلاً من ذلك، يمكنك إعداد كل توجيه على حدة داخل تطبيقك.

على الرغم من أنه يجب عليك عادة استخدام التوجيه كثير المورد (resourceful routing)، إلا أنه لا يزال هناك العديد من الأماكن التي يكون فيها التوجيه الأبسط أكثر ملاءمة. ليس هناك حاجة لمحاولة ارتداء كل جزء أخير من تطبيقك في إطار كثير المورد إذا لم يكن ذلك مناسبًا.

على وجه الخصوص، يجعل التوجيه البسيط من السهل جدًا تعيين عناوين URL القديمة لإجراءات Rails الجديدة.

المعاملات المقيدة

عند إعداد مسار عادي، فإنك تقدم سلسلة من الرموز التي تحددها Rails إلى أجزاء من طلب HTTP الوارد. على سبيل المثال، ضع في اعتبارك هذا المسار الموجه:

get 'photos(/:id)', to: :display

إذا تمت معالجة طلب وارد من ‎/photos/1 من خلال هذا التوجيه (لأنه لم يطابق أي توجيه سابق في الملف)، فستكون النتيجة استدعاء الإجراء display الذي يخص PhotosController، ولجعل المعامل النهائي "1"متاحًا بالشكل [params[:id. سيقوم هذا التوجيه أيضًا بتوجيه الطلب الوارد ‎/photos إلى DisplayController#display، نظرًا لأن المُعرِّف ‎:id هو مُعامل اختياري، يشار إليه بواسطة الأقواس.

الأجزاء الديناميكية

يمكنك إعداد العديد من الأجزاء الديناميكية (Dynamic Segments) ضمن مسار موجه عادي حسب رغبتك. سيكون أي جزء متاحًا للعمل كجزء من params. إذا أعددت المسار الموجه التالي:

get 'photos/:id/:user_id', to: 'photos#show'

سيرسل المسار الوارد ‎/photos/1/2 إلى الإجراء show الخاص بـ [PhotosController.params [:id. سيكون params[:id]‎ هو "1"، وسيكون [params[:user_id هو "2".

فائدة: بشكل افتراضي، لا تقبل الأجزاء الديناميكية النقاط، وهذا يرجع إلى استخدام النقطة كفاصل للمسارات الموجهة المنسقة. إذا كنت بحاجة إلى استخدام نقطة داخل جزء ديناميكي، أضف قيدًا يتجاوز هذا مثل ‎id: /[^\/]+/‎ الذي يسمح بأي شيء باستثناء الخط المستقيم المائل.

الأجزاء الثابتة

يمكنك تحديد الأجزاء الثابتة (Static Segments) عند إنشاء مسار موجه من خلال عدم إلحاق النقطتين بالجزء fragment:

get 'photos/:id/with_user/:user_id', to: 'photos#show'

يستجيب هذا المسار الموجه لمسارات مثل ‎/photos/1/with_user/2. في هذه الحالة، ستكون

المعاملات هي {controller: 'photos'، action: 'show'، id: '1'، user_id: '2ٌ'‎}.

سلسلة الاستعلام

ستشمل المعاملات أيضًا أي معاملات من سلسلة الاستعلام. على سبيل المثال، مع هذا المسار الموجه:

get 'photos/:id', to: 'photos#show'

سيرسل المسار الوارد ‎/photos/1?user_id=2 إلى الإجراء show الخاص بوحدة تحكم Photos. إن params ستكون { controller: 'photos', action: 'show', id: '1', user_id: '2'‎ }.

تحديد الافتراضات

يمكنك تحديد الإعدادات الافتراضية في المسار من خلال توفير تجزئة (hash) للخيار ‎:defaults. وينطبق هذا حتى على المعاملات التي لا تحددها كشرائح ديناميكية. فمثلًا:

get 'photos/:id', to: 'photos#show', defaults: { format: 'jpg' }

تطابق Rails المسار photos/12 مع الإجراء show الذي يخص showController، وتعين params[:format]‎ إلى "jpg".

يمكنك أيضًا استخدام defaults في تنسيق الكتلة لتحديد الإعدادات الافتراضية لعناصر متعددة:

defaults format: :json do

 resources :photos

end

ملاحظة: لا يمكنك إلغاء القيم الافتراضية عبر معاملات الاستعلام وهذا يعود لأسباب أمنية. القيم الافتراضية  الوحيدة التي يمكن تجاوزها هي الأجزاء الديناميكية عن طريق استبدالها في مسار URL.

تسمية المسارات الموجهة

يمكنك تحديد اسم لأي مسار موجه باستخدام الخيار ‎:as:

get 'exit', to: 'sessions#destroy', as: :logout

سيؤدي ذلك إلى إنشاء logout_path و logout_url كمساعدين مسميين في تطبيقك. وسيؤدي استدعاء loging_path إلى إعادة ‎/exit.

يمكنك أيضًا استخدام هذا لتجاوز توابع التوجيه المحددة بواسطة الموارد كما يلي:

get ':username', to: 'users#show', as: :user

سيحدد هذا التابع user_path الذي سيتاح في وحدات التحكم، والمساعدين والواجهات التي ستنتقل إلى مسار مثل ‎/bob. داخل الخيار show الخاص بـ UsersController، تحتوي [params[:username على اسم المستخدم للمستخدم. غير ‎:username في تعريف المسار الموجه إذا كنت لا تريد أن يكون اسم المعامل ‎:username.

قيود فعل HTTP

بشكل عام، يجب عليك استخدام التوابع get و post و put و patch و delete لتقييد توجيه إلى فعل معين. يمكنك استخدام التابع match مع الخيار ‎:via لمطابقة أفعال متعددة في وقت واحد:

match 'photos', to: 'photos#show', via: [:get, :post]

يمكنك مطابقة جميع الأفعال إلى مسار معين باستخدام via: :all كما يلي:

match 'photos', to: 'photos#show', via: :all

ملاحظة: توجيه كل من طلبيات GET و POST إلى إجراء واحد له آثار متعلقة بالأمان. بشكل عام، يجب تجنب توجيه جميع الأفعال إلى أي إجراء ما لم يكن لديك سبب وجيه لذلك.

ملاحظة: لن تتحقق طلبية GET في Rails من رمز CSRF (اختصار للعبارة cross-site request forgery، وهي الهجمات مُزوّرة الطلب عبر المواقع). يجب ألا تكتب أبدًا إلى قاعدة البيانات من طلبيات GET؛ لمزيد من المعلومات، انظر دليل الأمان الخاص بإجراءات CSRF المضادة.

قيود الجزء (Segment Constraints)

يمكنك استخدام الخيار ‎:constraints لفرض تنسيق لجزء ديناميكي بالشكل التالي:

get 'photos/:id', to: 'photos#show', constraints: { id: /[A-Z]\d{5}/ }

يطابق هذا المسار الموجه مسارات مثل ‎/photos/A12345، ولكن ليس ‎/photos/893. يمكنك التعبير بشكل أكثر دقة عن نفس التوجيه بهذه الطريقة:

get 'photos/:id', to: 'photos#show', id: /[A-Z]\d{5}/

تأخذ ‎:constraints تعبيرات نمطية مع القيود التي لا يمكن أن تستخدم مثبتات التعبير النمطي (regexp anchors). على سبيل المثال، لن يعمل التوجيه التالي:

get '/:id', to: 'articles#show', constraints: { id: /^\d/ }

ومع ذلك، لاحظ أنك لست بحاجة إلى استخدام نقاط تثبيت لأن جميع المسارات الموجهة المثبتة في البداية.

على سبيل المثال، تسمح التوجيهات التالية لـ articles التي لها قيم to_param مثل 1-hello-world والتي تبدأ دائمًا برقم ولـ users التي لها قيم to_param مثل david التي لا تبدأ برقم بمشاركة مجال الاسم الجذر (root namespace):

get '/:id', to: 'articles#show', constraints: { id: /\d.+/ }

get '/:username', to: 'users#show'

قيود على أساس الطلب

يمكنك أيضًا تقييد مسار موجه استنادًا إلى أي تابع في كائن الطلب Request التي يعيد سلسلة نصية.

يمكنك تحديد القيد على أساس الطلب بنفس الطريقة التي تحدد بها قيد الجزء (segment constraint):

get 'photos', to: 'photos#index', constraints: { subdomain: 'admin' }

يمكنك أيضًا تحديد القيود في نموذج الكتلة:

namespace :admin do

 constraints subdomain: 'admin' do

   resources :photos

 end

end

ملاحظة: تعمل قيود الطلب عن طريق استدعاء تابع في كائن الطلب Request يحمل نفس الاسم مثل مفتاح التجزئة (hash) ثم مقارنة القيمة المعادة بقيمة التجزئة. لذلك، يجب أن تتطابق قيم القيد مع نوع إرجاع تابع كائن الطلب المقابل. على سبيل المثال: { 'constraints: { subdomain: 'api سيطابق نطاقًا فرعيًا لواجهة برمجة التطبيق كما هو متوقع، ولكن لن يكون باستخدام رمز مثل

{ constraints: { subdomain: :api، نظرًا لأن request.subdomain يعرض "api" كسلسلة نصية.

ملاحظة: هناك استثناء للقيد format وهو في حين أنه تابع في كائن الطلب Request، وهو أيضًا معامل اختياري ضمني في كل مسار. يكون لقيود الشريحة الأسبقية وتطبق قيود التنسيق فقط عند فرضها عبر التجزئة. على سبيل المثال، get 'foo', constraints: { format: 'json' }‎ سيطابق GET  /foo

لأن التنسيق اختياري بشكل افتراضي. ومع ذلك، يمكنك استخدام تعابير lambda مثل

{ get 'foo', constraints: lambda { |req| req.format == :json وسيتطابق التوجيه مع طلبيات JSON الصريحة فقط.

القيود المتقدمة

إذا كان لديك قيد أكثر تقدمًا، يمكنك توفير كائن يستجيب إلى matches?‎ التي يجب أن تستخدمها Rails. لنفترض أنك تريد توجيه جميع المستخدمين في القائمة السوداء إلى BlacklistController، يمكنك القيام بذلك بالشكل التالي:

class BlacklistConstraint

 def initialize

   @ips = Blacklist.retrieve_ips

 end

 def matches?(request)

   @ips.include?(request.remote_ip)

 end

end

Rails.application.routes.draw do

 get '*path', to: 'blacklist#index',

   constraints: BlacklistConstraint.new

end

يمكنك أيضا تحديد القيود على أنها تعابير lambda:

Rails.application.routes.draw do

 get '*path', to: 'blacklist#index',

   constraints: lambda { |request| Blacklist.retrieve_ips.include?(request.remote_ip) }

end

كل من تابع matches?‎ و lambda يحصل على كائن الطلب Request كوسيط.

التوجيه النمطي والأجزاء المتطابقة بالمحارف الخاصة

التوجيه النمطي (Route globbing) هو طريقة لتحديد أنه يجب مطابقة معامل معين مع جميع الأجزاء المتبقية من المسار. فمثلًا:

get 'photos/*other', to: 'photos#unknown'

سيطابق هذا التوجيه المسار photos/12 أو /photos/long/path/to/12 مع تعيين [params[:other إلى "12" أو "long/path/to/12". تسمى الأجزاء المسبوقة بالرمز * باسم "الأجزاء المتطابقة بالمحارف الخاصة" (wildcard segments).

يمكن أن تظهر الأجزاء المتطابقة بالمحارف الخاصة في أي مكان في المسار. فمثلًا:

get 'books/*section/:title', to: 'books#show'

من شأنه أن يطابق books/some/section/last-words-a-memoir مع [params[:section الذي يساوي 'some/section'، ومع [params [:title الذي يساوي 'last-words-a-memoir'.

من الناحية الفنية، يمكن أن يحتوي المسار على أكثر من جزء واحدة متطابق. يعين المطابق (matcher) الأجزاء إلى معاملات بطريقة بديهية. فمثلًا:

get '*a/foo/*b', to: 'test#index'

سيطابق zoo/woo/foo/bar/baz مع [params[:a الذي يساوي 'zoo/woo'، ومع [params[:b الذي يساوي 'bar/baz'.

ملاحظة: عبر طلب '‎/foo/bar.json'، ستكون [params[:pages مساوية لـ '‎/foo/bar' مع تنسيق طلب JSON. إذا كنت تريد استعادة سلوك الإصدار ‎3.0.‎x القديم، فيمكنك توفير format: false بالشكل التالي:

get '*pages', to: 'pages#show', format: false

إذا كنت تريد جعل جزء التنسيق إلزاميًا، وبذلك لا يمكن حذفه، فيمكنك توفير format: true بالشكل التالي:

get '*pages', to: 'pages#show', format: true

إعادة التوجيه

يمكنك إعادة توجيه (redirect) أي مسار إلى مسار آخر باستخدام مساعد إعادة التوجيه redirect في المسار الموجه الخاص بك:

get '/stories', to: redirect('/articles')

يمكنك أيضًا إعادة استخدام أجزاء ديناميكية من المطابقة في المسار لإعادة التوجيه إلى:

get '/stories/:name', to: redirect('/articles/%{name}')

يمكنك أيضًا توفير حظر لإعادة التوجيه، والذي يتلقى معاملات المسار الرمزية وكائن الطلب Request:

get '/stories/:name', to: redirect { |path_params, req| "/articles/#{path_params[:name].pluralize}" }

get '/stories', to: redirect { |path_params, req| "/articles/#{req.subdomain}" }

يرجى ملاحظة أن إعادة التوجيه الافتراضية هي عملية إعادة توجيه 301 "تم نقلها بشكل دائم" (Moved Permanently). ضع في اعتبارك أن بعض متصفحات الويب أو الخوادم الوسيطة (proxy servers) ستخزن هذا النوع من إعادة التوجيه، مما يجعل الصفحة القديمة غير قابلة للوصول. يمكنك استخدام الخيار ‎:status لتغيير حالة الاستجابة:

get '/stories/:name', to: redirect('/articles/%{name}', status: 302)

في جميع هذه الحالات، إذا لم تقدم المضيف الأساسي (http://www.example.com)، فستأخذ Rails هذه التفاصيل من الطلب الحالي.

التوجيه إلى تطبيقات Rack

بدلاً من سلسلة نصية مثل 'articles#index'، والتي تتطابق مع الإجراء index في ArticlesController، يمكنك تحديد أي تطبيق Rack كنقطة نهاية للمطابق:

match '/application.js', to: MyRackApp, via: :all

طالما يستجيب MyRackApp لاستدعاء ويعيد [status, headers, body]، لن يعرف جهاز التوجيه الفرق بين تطبيق Rack والإجراء. هذا هو الاستخدام المناسب لـ via: :all، كما تريد السماح لتطبيق Rack الخاص بك بالتعامل مع جميع الأفعال التي تراها مناسبة.

ملاحظة: يوسع 'articles#index' فعليًا إلى (ArticlesController.action(:index، التي تُرجع تطبيق Rack صالحًا.

إذا قمت بتحديد تطبيق Rack كنقطة نهاية للمطابقة، فتذكر أنَّ التوجيه لن يتغير في تطبيق الاستلام. مع التوجيه التالي، يجب أن يتوقع تطبيق Rack أن يكون المسار هو ‎/admin:

match '/admin', to: AdminApp, via: :all

إذا كنت تفضل أن يتلقى تطبيق Rack طلبات على المسار الجذر بدلًا من ذلك، فاستخدم mount:

mount AdminApp, at: '/admin'

استخدام الجذر

يمكنك تحديد ما يجب أن تسلكه Rails عند توجيه '/' باستخدام التابع root:

root to: 'pages#main'

root 'pages#main' # shortcut for the above

يجب وضع مسار الجذر أعلى الملف، لأنه المسار الأكثر شيوعًا ويجب مطابقته أولاً.

ملاحظة: يوجه مسار الجذر فقط طلبيات GET إلى الإجراء.

يمكنك أيضًا استخدام الجذر داخل مجالات الأسماء والنطاقات أيضًا. فمثلًا:

namespace :admin do

 root to: "admin#index"

end

root to: "home#index"

توجيهات محارف يونيكود

يمكنك تحديد توجيهات محارف يونيكود مباشرةً. فمثلًا:

get 'こんにちは', to: 'welcome#index'

التوجيهات المباشرة

يمكنك إنشاء مساعدين مخصصين لعناوين URL مباشرةً. فمثلًا:

direct :homepage do

 "http://www.rubyonrails.org"

end

# >> homepage_url

# => "http://www.rubyonrails.org"

يجب أن تعيد الكتلة وسيطًا صالحًا للتابع url_for. لذلك، يمكنك تمرير سلسلة URL صحيحة، أو تجزئة، أو مصفوفة، أو نسخة نموذج نشط (Active Model instance)، أو صنف نموذج نشط (Active Model class).

direct :commentable do |model|

 [ model, anchor: model.dom_id ]

end

direct :main do

 { controller: 'pages', action: 'index', subdomain: 'www' }

end

استخدام resolve

يسمح التابع resolve بتخصيص تعيينات متعددة الأشكال (polymorphic mapping) للنماذج. فمثلًا:

resource :basket

resolve("Basket") { [:basket] }

<%= form_for @basket do |form| %>

 

<% end %>

سيؤدي ذلك إلى إنشاء عنوان URL هو  ‎/basket بدلًا من العنوان ‎/baskets/:id المعتاد.

تخصيص التوجيهات كثيرة الموارد

في حين أن التوجيهات والمساعدات الافتراضية التي أنشئت بواسطة resources :articles عادةً ما تخدمك جيدًا، فقد تحتاج إلى تخصيصها بطريقة ما. تسمح لك Rails بتخصيص أي جزء عام من المساعدين كثيري الموارد (resourceful helpers).

تحديد وحدة تحكم لاستخدامها

يتيح لك الخيار ‎:controller تحديد وحدة تحكم بشكل صريح لاستخدامها في المورد. فمثلًا:

resources :photos, controller: 'images'

سيتعرف على المسارات الواردة التي تبدأ بـ ‎/photos ولكن سيوجه إلى وحدة التحكم في Images:

فعل HTTP المسار وحدة التحكم#الإجراء مسمى المساعد
GET ‎/photos images#index photos_path
GET ‎/photos/new images#new new_photo_path
POST ‎/photos images#create photos_path
GET ‎/photos/:id images#show photo_path(:id)‎
GET ‎/photos/:id/edit images#edit edit_photo_path(:id)‎
PATCH/PUT ‎/photos/:id images#update photo_path(:id)‎
DELETE ‎/photos/:id images#destroy photo_path(:id)‎

ملاحظة: استخدم photos_photo و new_photo_path وما إلى ذلك لإنشاء مسارات لهذا المورد.

بالنسبة لوحدات تحكم ذات مجال أسماء (namespaced controllers)، يمكنك استخدام تدوين المجلد (directory notation). فمثلًا:

resources :user_permissions, controller: 'admin/user_permissions'

هذا سوف يوجهه إلى وحدة التحكم Admin::UserPermissions.

ملاحظة: تدوين المجلد مدعومٌ فقط. يمكن أن يؤدي تحديد وحدة التحكم بتدوين Ruby الثابت

(مثل controller: 'Admin::UserPermissions'‎) إلى مشاكل في التوجيه ينتج عنها تحذيرات.

تحديد القيود

يمكنك استخدام الخيار ‎:constraints لتحديد التنسيق المطلوب على المعرّف id الضمني. فمثلًا:

resources :photos, constraints: { id: /[A-Z][A-Z][0-9]+/ }

يقيد هذا الاعلان المعامل id: ليطابق التعبير المعتاد الموفر. لذلك، في هذه الحالة، لم يعد جهاز التوجيه يتطابق مع ‎/photos/1 مع هذا المسار. بدلًا من ذلك، إنَّ ‎/photos/RR27 هي من ستتطابق.

يمكنك تحديد قيد واحد لتطبيقه على عدد من المسارات باستخدام نموذج الكتلة:

constraints(id: /[A-Z][A-Z][0-9]+/) do

 resources :photos

 resources :accounts

End

ملاحظة: بالطبع، يمكنك استخدام القيود الأكثر تقدمًا المتوفرة في المسارات غير كثيرة الموارد في هذا السياق.

فائدة: بشكل افتراضي، لا يقبل المعامل ‎:id النقاط وذلك لأن النقطة تستخدم كفاصل للمسارات المنسقة. إذا كنت بحاجة إلى استخدام نقطة داخل ‎:id، فأدخل قيدًا يتجاوز هذا مثل id: /[^\/]+/‎ يسمح بأي شيء باستثناء الشرطة المائلة.

تجاوز المساعدين المسماة

يسمح لك الخيار ‎:as بتجاوز التسمية العادية لمساعدي مسار معين. فمثلًا:

resources :photos, as: 'images'

سوف يتعرف على المسارات الواردة التي تبدأ بـ ‎/photos ويوجه الطلبات إلى PhotosController، ولكن استخدم الخيار ‎:as لتسمية المساعدين.

فعل HTTP المسار وحدة التحكم # الإجراء مسمى المساعد
GET ‎/photos photos#index images_path
GET ‎/photos/new photos#new new_image_path
POST ‎/photos photos#create images_path
GET ‎/photos/:id photos#show image_path(:id)‎
GET ‎/photos/:id/edit photos#edit edit_image_path(:id)‎
PATCH/PUT ‎/photos/:id photos#update image_path(:id)‎
DELETE ‎/photos/:id photos#destroy image_path(:id)‎

استبدال الأجزاء الجديدة وتعديلها

يتيح لك الخيار ‎:path_names استبدال الأجزاء الجديدة وتعديلها تلقائيًا في المسارات:

resources :photos, path_names: { new: 'make', edit: 'change' }

قد يتسبب هذا في التعرف على المسارات مثل:

/photos/make

/photos/1/change

ملاحظة: لا تتغيير أسماء الإجراءات الفعلية بواسطة هذا الخيار. سيستمر المساران المعروضان في مسار التوجيه إلى الإجراءات الجديدة وتعديلها.

فائدة: إذا وجدت نفسك ترغب في تغيير هذا الخيار بشكل موحد لجميع مسارات التوجيه لديك، فيمكنك استخدام النطاق.

scope path_names: { new: 'make' } do

 # rest of your routes

end

إضافة بادئة لمساعدي مسار التوجيه المسمى

يمكنك استخدام الخيار ‎:as لإضافة بادئة لمساعدي مسار التوجيه المسمى الذي تُنشئُه Rails لمسار التوجيه. استخدم هذا الخيار لمنع تضارب الأسماء بين المسارات باستخدام نطاق مسار. فمثلًا:

scope 'admin' do

 resources :photos, as: 'admin_photos'

end

resources :photos

سيوفر ذلك مساعدين لمسارات التوجيه، مثل admin_photos_path و new_admin_photo_path وما إلى ذلك.

لإضافة بادئة لمجموعة من مساعدي مسارات التوجيه، استخدم الخيار ‎:as مع النطاق:

scope 'admin', as: 'admin' do

 resources :photos, :accounts

end

resources :photos, :accounts

سيؤدي ذلك إلى إنشاء مسارات مثل admin_photos_path و admin_accounts_path والتي تعين ‎/admin /photos و ‎/admin/accounts على التوالي.

ملاحظة: سيضيف نطاق مجال الأسماء تلقائيًا الخيار ‎:as بالإضافة إلى البادئات ‎:module و ‎:path.

يمكن إضافة بادئة لمسارات التوجيه مع معامل مسمى أيضًا:

scope ':username' do

 resources :articles

end

سيزودك هذا بعناوين URL مثل ‎/bob/articles/1 وسيسمح لك بمراجعة الجزء username من المسار

بالشكل [params[:username في وحدات التحكم والمساعدين والواجهات.

تقييد مسارات التوجيه التي أنشئت

بشكل افتراضي، تنشئ Rails مسارات توجيه للإجراءات الافتراضية السبعة (index، و show، و new، و create، و edit، و update، و destroy) لكل مسار RESTful في التطبيق الخاص بك. يمكنك استخدام الخيارات ‎:only و ‎:except لضبط هذا السلوك. الخيار ‎:only يخبر Rails بإنشاء المسارات المحددة فقط:

resources :photos, only: [:index, :show]

الآن، قد ينجح طلب GET إلى ‎/photos، ولكن سيخفق طلب POST إلى ‎/photos (والذي عادةً ما يوجه إلى إجراء create).

الخيار ‎:except يحدد المسار أو قائمة المسارات التي لا يجب على Rails أن تنشئها:

resources :photos, except: :destroy

في هذه الحالة، ستنشئ Rails  كل المسارات العادية باستثناء مسار التدمير (طلب DELETE إلى ‎/photos/:id).

فائدة: إذا كان التطبيق يحتوي على العديد من مسارات RESTful، فاستعمال ‎:only و ‎:except لتوليد مسارات التوجيه التي تحتاجها فعليًا فقط يمكن من تقليل استخدام الذاكرة وتسريع عملية التوجيه.

المسارات المبدَّلة

باستخدام scope، يمكننا تغيير أسماء المسارات التي أنشئت بواسطة resources:

scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do

 resources :categories, path: 'kategorien'

end

تنشئ Rails الآن مسارات إلى CategoriesContator.

فعل HTTP المسار وحدة التحكم # الإجراء مسمى المساعد
GET ‎/kategorien categories#index categories_path
GET ‎/kategorien/neu categories#new new_category_path
POST ‎/kategorien categories#create categories_path
GET ‎/kategorien/:id categories#show category_path(:id)‎
GET ‎/kategorien/:id/bearbeiten categories#edit edit_category_path(:id)‎
PATCH/PUT ‎/kategorien/:id categories#update category_path(:id)‎
DELETE /kategorien/:id categories#destroy category_path(:id)‎

استبدال النموذج المفرد

إذا كنت تريد تعريف الشكل المفرد لمورد، فيجب عليك إضافة قواعد إضافية إلى Inflector:

ActiveSupport::Inflector.inflections do |inflect|

 inflect.irregular 'tooth', 'teeth'

end

استخدام ‎:as في الموارد المتداخلة

الخيار ‎:as يستبدل الاسم الذي أُنشِأ تلقائيًا للمورد في مساعدي المسارات الموجهة المتداخلة. فمثلًا:

resources :magazines do

 resources :ads, as: 'periodical_ads'

end

سيؤدي ذلك إلى إنشاء مساعدين للتوجيه مثل magazine_periodical_ads_url و edit_magazine_periodical_ad_path.

استبدال معاملات المسار الموجه المسماة

يستبدل الخيار param: معرف المورد ‎:id الافتراضي (اسم الجزء الديناميكي المستخدم لإنشاء المسارات الموجهة). يمكنك الوصول إلى هذا الجزء من وحدة التحكم باستخدام params[<:param>]‎.

resources :videos, param: :identifier

   videos GET  /videos(.:format)                  videos#index

           POST /videos(.:format)                  videos#create

new_videos GET  /videos/new(.:format)              videos#new

edit_videos GET  /videos/:identifier/edit(.:format) videos#edit

Video.find_by(identifier: params[:identifier])

يمكنك استبدال ActiveRecord::Base#to_param لنموذج ذي صلة لإنشاء عنوان URL:

class Video < ApplicationRecord

 def to_param

   identifier

 end

end

video = Video.find_by(identifier: "Roman-Holiday")

edit_videos_path(video) # => "/videos/Roman-Holiday"

فحص واختبار المسارات الموجهة

توفر Rails أدوات ووسائل لفحص واختبار المسارات الموجهة الخاصة بك.

قائمة المسارات الحالية

للحصول على قائمة كاملة بالمسارات المتاحة في التطبيق الخاص بك، قم بزيارة http://localhost:3000/rails/info/routes في المستعرض الخاص بك أثناء تشغيل خادمك في بيئة التطوير. يمكنك أيضًا تنفيذ الأمر rails routes في الطرفية الخاصة بك لإنتاج نفس المخرجات.

ستقوم كلا الطريقتين بإدراج جميع مساراتك الموجهة بنفس الترتيب الذي تظهر به في config/routes.rb. لكل مسار، سترى:

  • اسم المسار الموجه (إن وجد).
  • الفعل HTTP المستخدم (إذا كان المسار لا يستجيب لكل الأفعال).
  • نمط عنوان URL المراد مطابقته.
  • معاملات التوجيه للمسار الموجه.

على سبيل المثال، إليك مقطع صغير من مخرجات الأمر rails routes لمسار RESTful الموجه:

   users GET    /users(.:format)          users#index

         POST /users(.:format)          users#create

new_user GET    /users/new(.:format)      users#new

edit_user GET    /users/:id/edit(.:format) users#edit

يمكنك البحث من خلال مساراتك الموجهة باستخدام الخيار  grep: -g. يظهر هذا الأمر أي مسارات موجهة تتطابق جزئيًا مع اسم تابع مساعد العنوان URL، أو فعل HTTP، أو مسار عنوان URL.

$ bin/rails routes -g new_comment

$ bin/rails routes -g POST

$ bin/rails routes -g admin

إذا كنت ترغب فقط في رؤية المسارات الموجهة التي تعين إلى وحدة تحكم معينة، فهناك الخيار ‎-c:

$ bin/rails routes -c users

$ bin/rails routes -c admin/users

$ bin/rails routes -c Comments

$ bin/rails routes -c Articles::CommentsController

فائدة: ستجد أن المخرجات من الأمر rails routes أكثر قابلية للقراءة إذا قمت بتوسيع نافذة طرفيتك حتى لا تلتف سطور المخرجات.

اختبار المسارات الموجهة

يجب تضمين المسارات الموجهة في إستراتيجية الاختبار (تمامًا مثل بقية تطبيقك). تقدم Rails ثلاثة تأكيدات مضمنة مصممة لجعل عملية اختبار المسارات الموجهة أكثر بساطة:

  • Assert_generates
  • Assert_recognizes
  • assert_routing

تأكيد assert_generates

يؤكد assert_generates أن مجموعة معينة من الخيارات تولد مسارًا معينًا ويمكن استخدامها مع المسارات الافتراضية أو المسارات المخصصة. إليك المثال التالي:

assert_generates '/photos/1', { controller: 'photos', action: 'show', id: '1' }

assert_generates '/about', controller: 'pages', action: 'about'

تأكيد assert_recognizes

هو عكس التأكيد assert_generates، إذ يؤكد أنه جرى التعرف على مسار معين ووُجِّه إلى مكان معين في التطبيق الخاص بك. إليك المثال التالي:

assert_recognizes({ controller: 'photos', action: 'show', id: '1' }, '/photos/1')

يمكنك توفير الوسيط method: لتحديد فعل HTTP:

assert_recognizes({ controller: 'photos', action: 'create' },

{ path: 'photos', method: :post })

تأكيد assert_routing

يتحقق تأكيد assert_routing من الطريقتين: يختبر أن المسار يولد الخيارات، وأن الخيارات تولد المسار. وبالتالي، فهو يجمع بين وظائف assert_generates و assert_recognizes:

assert_routing({ path: 'photos', method: :post }, { controller: 'photos', action: 'create' })

المصادر

  • الدليل الإرشادي لتوجيه Rails