التوجيه من الخارج إلى الداخل في ريلز
يغطي هذا الدليل الميزات التي يواجهها المستخدم في عمليات التوجيه في ريلز.
بعد قراءة هذا الدليل، ستعرف:
- كيفية تفسير الشيفرة في config/routes.rb.
- كيفية بناء المسارات الخاصة بك باستخدام إما أسلوب الحيلة (resourceful style) المفضل أو طريقة المطابقة (match method).
- كيفية الإعلان عن معاملات المسار الموجه، والتي تمرر إلى إجراءات وحدة التحكم (controller actions).
- كيفية إنشاء المسارات وعناوين URL تلقائيًا باستخدام مساعدي المسار الموجه.
- التقنيات المتقدمة مثل إنشاء قيود وتثبيت نقاط نهاية Rack.
الغرض من توجيه المسارات في ريلز
يتعرف جهاز التوجيه في ريلز على عناوين URL ويرسلها إلى إجراء وحدة التحكم Action Controller، أو إلى تطبيق Rack. ويمكنه أيضًا إنشاء مسارات وعناوين URL، مع تجنب الحاجة إلى استخدام رموز ثابتة في الواجهة الخاصة بك.
توصيل عناوين URL بالشيفرة
عندما يتلقى تطبيق ريلز طلبًا واردًا مثل: GET /patients/17
يطلب من جهاز التوجيه مطابقته مع إجراء وحدة تحكم Action Controller. إذا كان أول مسار مطابق هو:
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
لا تحتاج إلى التحديد في مساعد المسار الموجه.
تهيئة جهاز توجيه المسارات في ريلز
توجد المسارات الموجهة للتطبيق أو المحرك (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 ويجب عدم حذفه.
توجيه المورد: الافتراضي في ريلز
يتيح لك توجيه الموارد إمكانية الإعلان بسرعة عن جميع المسارات الشائعة لوحدة التحكم كثيرة الموارد. بدلًا من الإعلان عن مسارات موجهة منفصلة للإجراءات index
، و show
، و new
، و edit
، و create
، و update
و destroy
الخاصة بك، فإن المسار كثير المورد يعلن عنه في سطر واحد من الشيفرة.
الموارد على الويب
تطلب صفحات المتصفحات من ريلز عن طريق تقديم طلب لعنوان URL باستخدام تابع HTTP محدد، مثل GET و POST و PATCH و PUT و DELETE. كل تابع هو طلب لتنفيذ عملية على المورد. يحدد مسار المورد الموجه عددًا من الطلبات ذات الصلة بالإجراءات في وحدة التحكم الواحدة.
عندما يتلقى تطبيق ريلز طلبًا واردًا لما يلي:
DELETE /photos/17
يطلب من جهاز التوجيه لتعيينه إلى إجراء وحدة تحكم Action Controller. إذا كان أول مسار مطابق هو:
resources :photos
سترسل ريلز ذلك الطلب للإجراء destroy
على وحدة التحكم photos
مع {id: '17'}
في params
.
CRUD والأفعال والإجراءات
في ريلز، يوفر المسار كثير المورد تخطيطًا بين أفعال 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 تتحول إلى سبعة إجراءات مختلفة.
ملاحظة: تُطابَق مسارات ريلز بالترتيب المحدد لها، لذلك إذا كانت لديك 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
، ستنشئ ريلز:
فعل 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)
|
إذا كنت تريد توجيه /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) في مقالة شائعة له قاعدةً أساسيةً لتصميم ريلز بشكل جيد: " لا ينبغي أبدًا أن تتداخل الموارد أكثر من 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
|
DELETE | /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
مع مجموعة من الكائنات، وسوف تحدد ريلز المسار الموجهة الذي تريده تلقائيًا:
<%= link_to 'Ad details', url_for([@magazine, @ad]) %>
في هذه الحالة، سترى ريلز أن 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
سيؤدي هذا إلى تمكين ريلز للتعرف على مسارات مثل /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
سيؤدي هذا إلى تمكين ريلز للتعرف على مسارات مثل /comments/new/preview باستخدام GET، وتوجيهها إلى الإجراء preview
الذي يخص CommentController
. سيؤدي أيضًا إلى إنشاء مساعدي التوجيه preview_new_comment_url
و preview_new_comment_path
.
فائدة: إذا وجدت نفسك تضيف العديد من الإجراءات الإضافية إلى مسار موجه ذي أهمية، فقد حان الوقت للتوقف وسؤال نفسك ما إذا كنت تموه عن وجود مورد آخر.
المسارات الموجهة غير كثيرة المورد (Non-Resourceful)
بالإضافة إلى توجيه الموارد، تتمتع ريلز بدعم قوي لتوجيه عناوين URL العشوائية إلى الإجراءات. هنا، لا يمكنك الحصول على مجموعات من التوجيهات التي تنشأ تلقائيًا من خلال توجيه الموارد. بدلاً من ذلك، يمكنك إعداد كل توجيه على حدة داخل تطبيقك.
على الرغم من أنه يجب عليك عادة استخدام التوجيه كثير المورد (resourceful routing)، إلا أنه لا يزال هناك العديد من الأماكن التي يكون فيها التوجيه الأبسط أكثر ملاءمة. ليس هناك حاجة لمحاولة ارتداء كل جزء أخير من تطبيقك في إطار كثير المورد إذا لم يكن ذلك مناسبًا.
على وجه الخصوص، يجعل التوجيه البسيط من السهل جدًا تعيين عناوين URL القديمة لإجراءات ريلز الجديدة.
المعاملات المقيدة
عند إعداد مسار عادي، فإنك تقدم سلسلة من الرموز التي تحددها ريلز إلى أجزاء من طلب 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' }
تطابق ريلز المسار 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 في ريلز من رمز 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) ثم مقارنة القيمة المعادة بقيمة الجدول 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?
التي يجب أن تستخدمها ريلز. لنفترض أنك تريد توجيه جميع المستخدمين في القائمة السوداء إلى 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)، فستأخذ ريلز هذه التفاصيل من الطلب الحالي.
التوجيه إلى تطبيقات 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 abov
يجب وضع مسار الجذر أعلى الملف، لأنه المسار الأكثر شيوعًا ويجب مطابقته أولاً.
ملاحظة: يوجه مسار الجذر فقط طلبيات 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 صحيحة، أو جدول Hash، أو مصفوفة، أو نسخة من Active Model، أو صنف من Active Model:
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| %>
<!-- basket form -->
<% end %>
سيؤدي ذلك إلى إنشاء عنوان URL هو /basket بدلًا من العنوان /baskets/:id المعتاد.
تخصيص التوجيهات كثيرة الموارد
في حين أن التوجيهات والمساعدات الافتراضية التي أنشئت بواسطة resources :articles
عادةً ما تخدمك جيدًا، فقد تحتاج إلى تخصيصها بطريقة ما. تسمح لك ريلز بتخصيص أي جزء عام من المساعدين كثيري الموارد (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
.
ملاحظة: تدوين المجلد مدعومٌ فقط. يمكن أن يؤدي تحديد وحدة التحكم بتدوين روبي الثابت
(مثل 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
لإضافة بادئة لمساعدي مسار التوجيه المسمى الذي تُنشئُه ريلز لمسار التوجيه. استخدم هذا الخيار لمنع تضارب الأسماء بين المسارات باستخدام نطاق مسار. فمثلًا:
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
في وحدات التحكم والمساعدين والواجهات.
تقييد مسارات التوجيه التي أنشئت
بشكل افتراضي، تنشئ ريلز مسارات توجيه للإجراءات الافتراضية السبعة (index
، و show
، و new
، و create
، و edit
، و update
، و destroy
) لكل مسار RESTful في التطبيق الخاص بك. يمكنك استخدام الخيارات :only
و :except
لضبط هذا السلوك. الخيار :only
يخبر ريلز بإنشاء المسارات المحددة فقط:
resources :photos, only: [:index, :show]
الآن، قد ينجح طلب GET إلى /photos، ولكن سيخفق طلب POST إلى /photos (والذي عادةً ما يوجه إلى الإجراء create
).
الخيار :except
يحدد المسار أو قائمة المسارات التي لا يجب على ريلز أن تنشئها:
resources :photos, except: :destroy
في هذه الحالة، ستنشئ ريلز كل المسارات العادية باستثناء مسار التدمير (طلب DELETE إلى /photos/:id).
فائدة: إذا كان التطبيق يحتوي على العديد من مسارات RESTful، فاستعمال :only
و :except
لتوليد مسارات التوجيه التي تحتاجها فعليًا فقط يمكن من تقليل استخدام الذاكرة وتسريع عملية التوجيه.
المسارات المبدَّلة
باستخدام scope
، يمكننا تغيير أسماء المسارات التي أنشئت بواسطة resources
:
scope(path_names: { new: 'neu', edit: 'bearbeiten' }) do
resources :categories, path: 'kategorien'
end
تنشئ ريلز الآن مسارات موجهة إلى 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"
فحص واختبار المسارات الموجهة
توفر ريلز أدوات ووسائل لفحص واختبار المسارات الموجهة الخاصة بك.
قائمة المسارات الحالية
للحصول على قائمة كاملة بالمسارات المتاحة في التطبيق الخاص بك، قم بزيارة 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
أكثر قابلية للقراءة إذا قمت بتوسيع نافذة طرفيتك حتى لا تلتف سطور المخرجات.
اختبار المسارات الموجهة
يجب تضمين المسارات الموجهة في إستراتيجية الاختبار (تمامًا مثل بقية تطبيقك). تقدم ريلز ثلاثة تأكيدات مضمنة مصممة لجعل عملية اختبار المسارات الموجهة أكثر بساطة:
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' })