الفرق بين المراجعتين لصفحة: «Rails/routing»

من موسوعة حسوب
تنسيق الشيفرات
طلا ملخص تعديل
 
(1 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 1: سطر 1:
<noinclude>{{DISPLAYTITLE:التوجيه من الخارج إلى الداخل في ريلز}}</noinclude>
<noinclude>{{DISPLAYTITLE:التوجيه من الخارج إلى الداخل في ريلز}}</noinclude>
[[تصنيف:Rails]]
[[تصنيف:Rails]]
[[تصنيف:Rails Controllers]]
يغطي هذا الدليل الميزات التي يواجهها المستخدم في عمليات التوجيه في ريلز.
يغطي هذا الدليل الميزات التي يواجهها المستخدم في عمليات التوجيه في ريلز.


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


== الغرض من توجيه المسارات في ريلز ==
== الغرض من توجيه المسارات في ريلز ==
يتعرف جهاز التوجيه في ريلز على عناوين URL ويرسلها إلى إجراء وحدة التحكم، أو إلى تطبيق Rack. ويمكنه أيضًا إنشاء مسارات وعناوين URL، مع تجنب الحاجة إلى استخدام رموز ثابتة في الواجهة الخاصة بك.
يتعرف جهاز التوجيه في ريلز على عناوين URL ويرسلها إلى إجراء وحدة التحكم [[Rails/action controller overview|Action Controller]]، أو إلى تطبيق Rack. ويمكنه أيضًا إنشاء مسارات وعناوين URL، مع تجنب الحاجة إلى استخدام رموز ثابتة في الواجهة الخاصة بك.


=== توصيل عناوين URL بالشيفرة ===
=== توصيل عناوين URL بالشيفرة ===
عندما يتلقى تطبيق ريلز طلبًا واردًا مثل: <code>GET /patients/17</code> يطلب من جهاز التوجيه مطابقته مع إجراء وحدة تحكم. إذا كان أول مسار مطابق هو:<syntaxhighlight lang="rails">
عندما يتلقى تطبيق ريلز طلبًا واردًا مثل: <code>GET /patients/17</code> يطلب من جهاز التوجيه مطابقته مع إجراء وحدة تحكم [[Rails/action controller overview|Action Controller]]. إذا كان أول مسار مطابق هو:<syntaxhighlight lang="rails">
get '/patients/:id', to: 'patients#show'
get '/patients/:id', to: 'patients#show'
</syntaxhighlight>يرسل الطلب إلى وحدة التحكم <code>patients</code> الخاص بالإجراء <code>show</code> مع <code>{ id: '17' }</code> في <code>params</code>.
</syntaxhighlight>يرسل الطلب إلى وحدة التحكم <code>patients</code> الخاص بالإجراء <code>show</code> مع <code>{ id: '17' }</code> في <code>params</code>.
سطر 49: سطر 50:
عندما يتلقى تطبيق ريلز طلبًا واردًا لما يلي:<syntaxhighlight lang="http">
عندما يتلقى تطبيق ريلز طلبًا واردًا لما يلي:<syntaxhighlight lang="http">
DELETE /photos/17
DELETE /photos/17
</syntaxhighlight>يطلب من جهاز التوجيه لتعيينه إلى إجراء وحدة تحكم. إذا كان أول مسار مطابق هو:<syntaxhighlight lang="rails">
</syntaxhighlight>يطلب من جهاز التوجيه لتعيينه إلى إجراء وحدة تحكم [[Rails/action controller overview|Action Controller]]. إذا كان أول مسار مطابق هو:<syntaxhighlight lang="rails">
resources :photos
resources :photos
</syntaxhighlight>سترسل ريلز ذلك الطلب للإجراء <code>destroy</code> على وحدة التحكم <code>photos</code> مع <code>{id: '17'}</code> في <code>params</code>.
</syntaxhighlight>سترسل ريلز ذلك الطلب للإجراء <code>destroy</code> على وحدة التحكم <code>photos</code> مع <code>{id: '17'}</code> في <code>params</code>.
سطر 100: سطر 101:
'''ملاحظة''': نظرًا لأن جهاز التوجيه يستخدم الفعل HTTP وعنوان URL لمطابقة الطلبات الواردة، فإن أربعة عناوين URL تتحول إلى سبعة إجراءات مختلفة.
'''ملاحظة''': نظرًا لأن جهاز التوجيه يستخدم الفعل HTTP وعنوان URL لمطابقة الطلبات الواردة، فإن أربعة عناوين URL تتحول إلى سبعة إجراءات مختلفة.


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


=== المسار ومساعد URL ===
=== المسار ومساعد URL ===
سطر 410: سطر 411:
|<code>comment_path</code>
|<code>comment_path</code>
|-
|-
|
|DELETE
|‎/sekret/comments/:id(.:format)‎
|‎/sekret/comments/:id(.:format)‎
|<code>comments#destroy</code>
|<code>comments#destroy</code>
سطر 636: سطر 637:
   end
   end
end
end
</syntaxhighlight>'''ملاحظة''': تعمل قيود الطلب عن طريق استدعاء تابع في كائن الطلب <code>Request</code> يحمل نفس الاسم مثل مفتاح التجزئة (hash) ثم مقارنة القيمة المعادة بقيمة التجزئة. لذلك، يجب أن تتطابق قيم القيد مع نوع إرجاع تابع كائن الطلب المقابل. على سبيل المثال: <code>{ 'constraints: { subdomain: 'api</code> سيطابق نطاقًا فرعيًا لواجهة برمجة التطبيق كما هو متوقع، ولكن لن يكون باستخدام رمز مثل
</syntaxhighlight>'''ملاحظة''': تعمل قيود الطلب عن طريق استدعاء تابع في كائن الطلب <code>Request</code> يحمل نفس الاسم مثل مفتاح التجزئة (hash) ثم مقارنة القيمة المعادة بقيمة الجدول Hash. لذلك، يجب أن تتطابق قيم القيد مع نوع إرجاع تابع كائن الطلب المقابل. على سبيل المثال: <code>{ 'constraints: { subdomain: 'api</code> سيطابق نطاقًا فرعيًا لواجهة برمجة التطبيق كما هو متوقع، ولكن لن يكون باستخدام رمز مثل


<code>{ constraints: { subdomain: :api</code>، نظرًا لأن <code>request.subdomain</code> يعرض <code>"api"</code> كسلسلة نصية.
<code>{ constraints: { subdomain: :api</code>، نظرًا لأن <code>request.subdomain</code> يعرض <code>"api"</code> كسلسلة نصية.
سطر 738: سطر 739:
# >> homepage_url
# >> homepage_url
# => "http://www.rubyonrails.org"
# => "http://www.rubyonrails.org"
</syntaxhighlight>يجب أن تعيد الكتلة وسيطًا صالحًا للتابع <code>url_for</code>. لذلك، يمكنك تمرير سلسلة URL صحيحة، أو تجزئة، أو مصفوفة، أو نسخة نموذج نشط (Active Model instance)، أو صنف نموذج نشط (Active <syntaxhighlight lang="rails">
</syntaxhighlight>يجب أن تعيد الكتلة وسيطًا صالحًا للتابع <code>url_for</code>. لذلك، يمكنك تمرير سلسلة URL صحيحة، أو جدول Hash، أو مصفوفة، أو نسخة من [[Rails/active model|Active Model]]، أو صنف من [[Rails/active model|Active Model]]: <syntaxhighlight lang="rails">
direct :commentable do |model|
direct :commentable do |model|
   [ model, anchor: model.dom_id ]
   [ model, anchor: model.dom_id ]
سطر 880: سطر 881:
يتيح لك الخيار <code>‎:path_names</code> استبدال الأجزاء الجديدة وتعديلها تلقائيًا في المسارات:<syntaxhighlight lang="rails">
يتيح لك الخيار <code>‎:path_names</code> استبدال الأجزاء الجديدة وتعديلها تلقائيًا في المسارات:<syntaxhighlight lang="rails">
resources :photos, path_names: { new: 'make', edit: 'change' }
resources :photos, path_names: { new: 'make', edit: 'change' }
</syntaxhighlight>قد يتسبب هذا في التعرف على المسارات مثل:
</syntaxhighlight>قد يتسبب هذا في التعرف على المسارات مثل:<syntaxhighlight lang="text">
 
/photos/make
/photos/make


/photos/1/change
/photos/1/change
 
</syntaxhighlight>'''ملاحظة''': لا تتغيير أسماء الإجراءات الفعلية بواسطة هذا الخيار. سيستمر المساران المعروضان في مسار التوجيه إلى الإجراءات الجديدة وتعديلها.
'''ملاحظة''': لا تتغيير أسماء الإجراءات الفعلية بواسطة هذا الخيار. سيستمر المساران المعروضان في مسار التوجيه إلى الإجراءات الجديدة وتعديلها.


'''فائدة''': إذا وجدت نفسك ترغب في تغيير هذا الخيار بشكل موحد لجميع مسارات التوجيه لديك، فيمكنك استخدام النطاق.<syntaxhighlight lang="rails">
'''فائدة''': إذا وجدت نفسك ترغب في تغيير هذا الخيار بشكل موحد لجميع مسارات التوجيه لديك، فيمكنك استخدام النطاق.<syntaxhighlight lang="rails">
سطر 911: سطر 910:
</syntaxhighlight>سيؤدي ذلك إلى إنشاء مسارات مثل <code>admin_photos_path</code> و <code>admin_accounts_path</code> والتي تعين ‎/admin /photos و ‎/admin/accounts على التوالي.
</syntaxhighlight>سيؤدي ذلك إلى إنشاء مسارات مثل <code>admin_photos_path</code> و <code>admin_accounts_path</code> والتي تعين ‎/admin /photos و ‎/admin/accounts على التوالي.


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


يمكن إضافة بادئة لمسارات التوجيه مع معامل مسمى أيضًا:<syntaxhighlight lang="rails">
يمكن إضافة بادئة لمسارات التوجيه مع معامل مسمى أيضًا:<syntaxhighlight lang="rails">

المراجعة الحالية بتاريخ 10:20، 24 مارس 2019

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

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

  • كيفية تفسير الشيفرة في 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' })

المصادر