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

من موسوعة حسوب
لا ملخص تعديل
طلا ملخص تعديل
 
(4 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 1: سطر 1:
تخطيط الصفحات والتصيير في ريلز
<noinclude>{{DISPLAYTITLE:تخطيط الصفحات والتصيير في ريلز}}</noinclude>
 
[[تصنيف:Rails]]
يغطي هذا الدليل ميزات التخطيط الأساسية لوحدتي [[Rails/action controller overview|التحكم]] و<nowiki/>[[Rails/action view overview|العرض]].
[[تصنيف:Rails View]]
 
يغطي هذا الدليل ميزات التخطيط الأساسية لوحدتي [[Rails/action controller overview|التحكم]] و<nowiki/>[[Rails/action view overview|العرض]]. بعد قراءة هذا الدليل، ستتعلم:
بعد قراءة هذا الدليل، ستتعلم:
* كيفية استخدام توابع التصيير المختلفة المضمنة ‎في ريلز.
* كيفية استخدام توابع التصيير المختلفة المضمنة ‎في ريلز.
* كيفية إنشاء تخطيطات (layouts) تحتوي على أقسام محتوى متعددة.
* كيفية إنشاء تخطيطات (layouts) تحتوي على أقسام محتوى متعددة.
سطر 10: سطر 9:


== نظرة عامة: كيف تتراكب قطع الأحجية معًا ==
== نظرة عامة: كيف تتراكب قطع الأحجية معًا ==
يركز هذا الدليل على التفاعل بين [[Rails/action controller overview|المتحكم]] و<nowiki/>[[Rails/action view overview|العرض]] في نمط التصميم Model-View-Controller. كما تعلم، فإنَّ المتحكم مسؤول عن تنظيم العملية الكاملة للتعامل مع الطلب في ريلز، على الرغم من أنه عادة لا يتعامل مع أي شيفرة ثقيلة في النموذج. ولكن بعد ذلك، عندما يحين وقت إرسال رد مرة أخرى إلى المستخدم، يسلم المتحكم بعض الأشياء إلى وحدة العرض. إنه التبادل الذي هو موضوع هذا الدليل.
يركز هذا الدليل على التفاعل بين [[Rails/action controller overview|المتحكم]] و<nowiki/>[[Rails/action view overview|العرض]] في نمط التصميم '''M'''odel-'''V'''iew-'''C'''ontroller. كما تعلم، فإنَّ المتحكم مسؤول عن تنظيم العملية الكاملة للتعامل مع الطلب في ريلز، على الرغم من أنه عادة لا يتعامل مع أي شيفرة ثقيلة في النموذج. ولكن بعد ذلك، عندما يحين وقت إرسال رد مرة أخرى إلى المستخدم، يسلم المتحكم بعض الأشياء إلى وحدة العرض. إنه التبادل الذي هو موضوع هذا الدليل.


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


== إنشاء الردود ==
== إنشاء الردود ==
سطر 177: سطر 176:
</syntaxhighlight>'''تنويه''': يجب استخدام هذا الخيار فقط إذا كنت لا تهتم بنوع محتوى الرد (الاستجابة). استخدام الخيار <code>:plain</code> أو <code>:html</code> قد يكون أكثر ملاءمة معظم الأوقات.
</syntaxhighlight>'''تنويه''': يجب استخدام هذا الخيار فقط إذا كنت لا تهتم بنوع محتوى الرد (الاستجابة). استخدام الخيار <code>:plain</code> أو <code>:html</code> قد يكون أكثر ملاءمة معظم الأوقات.


'''ملاحظة''': ما لم يُستبدَل، فإن ردك المُعاد من استعمال الخيار هذا مع التابع <code>render</code> سيكون من النوع text/plain، لأن هذا هو نوع المحتوى الافتراضي لرد الإجراء Dispatch.
'''ملاحظة''': ما لم يُستبدَل، فإن ردك المُعاد من استعمال الخيار هذا مع التابع <code>render</code> سيكون من النوع text/plain، لأن هذا هو نوع المحتوى الافتراضي لرد Action Dispatch.


==== خيارات أخرى ====
==== خيارات أخرى ====
سطر 462: سطر 461:


==== البحث عن التخطيطات ====
==== البحث عن التخطيطات ====
للعثور على التخطيط الحالي، تبحث ريلز أولًا عن ملف في app/views/layouts بنفس الاسم الأساسي للمتحكم. على سبيل المثال، سيؤدي استخدام إجراءات من الصنف <code>PhotosController</code> إلى استخدام app/views/layouts/photos.html.erb (أو app/views/layouts/photos.builder). إذا لم يكن هناك تخطيط محدد لهذا المتحكم، فستستخدم ريلز app/views/layouts/application.html.erb أو app/views/layouts/application.builder. إذا لم يكن هناك تخطيط ‎<code>.erb</code>، فسوف يستخدم ريلز التخطيط ‎<code>.builder</code> إذا كان موجودًا. توفر ريلز أيضًا عدة طرق لتعيين تخطيطات محددة بدقة أكبر لمتحكمات وأحداث فردية.
للعثور على التخطيط الحالي، تبحث ريلز أولًا عن ملف في app/views/layouts بنفس الاسم الأساسي للمتحكم. على سبيل المثال، سيؤدي استخدام [[Rails/action view|Action View]] من الصنف <code>PhotosController</code> إلى استخدام app/views/layouts/photos.html.erb (أو app/views/layouts/photos.builder). إذا لم يكن هناك تخطيط محدد لهذا المتحكم، فستستخدم ريلز app/views/layouts/application.html.erb أو app/views/layouts/application.builder. إذا لم يكن هناك تخطيط ‎<code>.erb</code>، فسوف يستخدم ريلز التخطيط ‎<code>.builder</code> إذا كان موجودًا. توفر ريلز أيضًا عدة طرق لتعيين تخطيطات محددة بدقة أكبر لمتحكمات وأحداث فردية.


===== تحديد التخطيطات للمتحكمات =====
===== تحديد التخطيطات للمتحكمات =====
سطر 578: سطر 577:
</syntaxhighlight>
</syntaxhighlight>


===== تجنب أخطاء التصيير الثنائي =====
===== تجنب أخطاء التصيير المضاعف =====
عاجلاً أم آجلاً، سيشاهد معظم مطوري ريلز رسالة الخطأ "لا يمكن عرض أو إعادة التوجيه إلا مرة واحدة لكل حدث". في حين أن هذا أمر مزعج، فإنه من السهل نسبيًا إصلاحه. عادة ما يحدث ذلك بسبب سوء فهم أساسي للطريقة التي تعمل.
عاجلًا أم آجلًا، سيشاهد معظم مطوري ريلز رسالة الخطأ "Can only render or redirect once per action" (أي لا يمكن عرض أو إعادة التوجيه إلا مرة واحدة لكل إجراء). في حين أن هذا أمر مزعج، فإنه من السهل نسبيًا إصلاحه. عادة ما يحدث ذلك بسبب سوء فهم أساسي للطريقة التي تعمل التابع <code>render</code> بها.
 
على سبيل المثال، إليك بعض الشيفرات التي ستؤدي إلى ظهور هذا الخطأ:


على سبيل المثال، إليك بعض الشيفرات التي ستؤدي إلى ظهور هذا الخطأ:<syntaxhighlight lang="rails">
def show
def show
 
  @book = Book.find(params[:id])
 @book = Book.find(params[:id])
  if @book.special?
 
    render action: "special_show"
 if @book.special?
  end
 
  render action: "regular_show"
   render action: "special_show"
 
 end
 
 render action: "regular_show"
 
end
end
 
</syntaxhighlight>إذا كان الاستدعاء <code>‎@book.special?</code>‎ يعيد القيمة <code>true</code>، سيبدأ ريلز عملية التصيير لتفريغ المتغير <code>book@</code> في العرض <code>special_show</code>. ولكن هذا لن يوقف بقية الشيفرة في الإجراء <code>show</code> من العمل، وعندما تصل ريلز إلى نهاية الإجراء، فإنه سيبدأ في بتصيير العرض <code>regular_show</code>، وإلقاء خطأ. الحل بسيط: تأكد من استدعاء <code>render</code> أو <code>redirect</code> مرةً واحدةً في الوقت ذاته في الشيفرة نفسها. شيء آخر يمكن أن يساعد هو استعمال <code>and return</code>. وإليك نسخة مصححة من المثال السابق:<syntaxhighlight lang="rails">
إذا كان @ book.special؟ يقيّم إلى true ، سيبدأ ريلز عملية العرض لتفريغ المتغيرbook في طريقة العرض special_show. ولكن هذا لن يوقف بقية الشيفرة في الحدث المعروض من التشغيل، وعندما تصل ريلز إلى نهاية الحدث، فإنه سيبدأ في عرض regular_show، وإلقاء خطأ. الحل بسيط: تأكد من أن لديك استدعاء واحد فقط لعرض أو إعادة توجيه في مسار شيفرة واحد. شيء واحد يمكن أن يساعد هو and return. وإليك نسخة مصححة من الدالة:
 
def show
def show
 
  @book = Book.find(params[:id])
 @book = Book.find(params[:id])
  if @book.special?
 
    render action: "special_show" and return
 if @book.special?
  end
 
  render action: "regular_show"
   render action: "special_show" and return
 
 end
 
 render action: "regular_show"
 
end
end
</syntaxhighlight>تأكد من استخدام <code>and return</code> بدلًا من <code>return &&</code> لأن الأخيرة لن تعمل نتيجة أسبقية المعامل في لغة [[Ruby|روبي]].


تأكد من استخدام and return  بدلًا من return && لأن return && لن تعمل نتيجة أسبقية المشغل في لغة Ruby.
لاحظ أنَّ التصيير الضمني الذي قام به المتحكم <code>ActionController</code> يكتشف إذا استُدعي <code>render</code>، لذلك ستعمل الشيفرة التالية دون أخطاء:<syntaxhighlight lang="rails">
 
لاحظ أن العرض الضمني الذي قام به ActionCroller يكتشف إذا استُدعي العارض، لذلك يعمل التالي دون أخطاء:
 
def show
def show
 
  @book = Book.find(params[:id])
 @book = Book.find(params[:id])
  if @book.special?
 
    render action: "special_show"
 if @book.special?
  end
 
   render action: "special_show"
 
 end
 
end
end
</syntaxhighlight>هذا سيصيِّر كتابًا (<code>book</code>) مع ضبط <code>special?‎</code> مع القالب <code>special_show</code>، بينما ستصيَّر الكتب الأخرى باستخدام القالب <code>show</code> الافتراضي.


هل هذا سيعرض book بشكل خاص؟ ضع مع قالب special_show، بينما ستُعرض الكتب الأخرى باستخدام قالب العرض الافتراضي.
=== استخدام <code>redirect_to</code> ===
 
هناك طريقة أخرى لمعالجة الاستجابات العائدة من طلبية HTTP وهي <code>redirect_to</code>. كما شاهدت، يخبر التابع <code>render</code> ريلز أي عرض (أو أصل آخر) سيُستخدَم في إنشاء استجابة. يفعل التابع <code>redirect_to</code> شيئًا مختلفًا تمامًا؛ فهو يخبر المتصفح بإرسال طلبية جديدة لعنوان URL مختلف. على سبيل المثال، يمكنك إعادة التوجيه من أي مكان توجد فيه في شيفرتك إلى فهرس الصور في تطبيقك باستخدام هذا الاستدعاء:<syntaxhighlight lang="rails">
== 2.3 استخدام redirect_to ==
هناك طريقة أخرى لمعالجة الاستجابات العائدة لطلب HTTP وهي redirect_to. كما شاهدت، render يخبر ريلز أي عرض (أو أصل آخر) سيستخدم في إنشاء استجابة. تعمل دالة redirect_to شيئًا مختلفًا تمامًا: فهي تخبر المتصفح بإرسال طلب جديد لعنوان URL مختلف. على سبيل المثال، يمكنك إعادة التوجيه من أي مكان توجد فيه في شيفرتك إلى فهرس الصور في تطبيقك باستخدام هذا الاستدعاء:
 
redirect_to photos_url
redirect_to photos_url
 
</syntaxhighlight>يمكنك استخدام <code>redirect_back</code> لإعادة المستخدم إلى الصفحة التي جاء منها للتو. يُسحَب هذا الموقع من الترويسة <code>HTTP_REFERER</code> التي لا يُضمَن أن يضبطها المتصفح، لذلك يجب تمرير <code>fallback_location</code> لاستخدامه في هذه الحالة.<syntaxhighlight lang="rails">
يمكنك استخدام redirect_back لإعادة المستخدم إلى الصفحة التي جاء منها للتو. يُسحَب هذا الموقع من رأس HTTP_REFERER الذي لا يضمنه المتصفح، لذلك يجب توفير fallback_location لاستخدامه في هذه الحالة.
 
redirect_back(fallback_location: root_path)
redirect_back(fallback_location: root_path)
</syntaxhighlight>'''ملاحظة''': لا يتوقف كل من <code>redirect_to</code> و <code>redirect_back</code> ويعودان فورًا من تنفيذ التابع، ولكن ببساطة يعينان استجابات HTTP. ستنفَّذ التعليمات البرمجية التي بعدهما في تابعٍ. يمكنك إيقاف التنفيذ عن طريق استعمال <code>return</code> بصراحة أو باستعمال آلية إيقاف أخرى، إذا لزم الأمر.


ملاحظة: لا يتوقف كل من redirect_to و redirect_back ويعودان فورًا من تنفيذ الدالة، ولكن ببساطة يعينان استجابات HTTP. ستنفذ العبارات التي تحدث بعدها في الدالة. يمكنك التوقف عن طريق العودة الصريحة أو بعض آلية التوقف الأخرى، إذا لزم الأمر.
==== الحصول على رمز حالة مختلف لإعادة التوجيه ====
 
يستخدم ريلز رمز الحالة HTTP 302 الذي يشير إلى إعادة توجيه مؤقتة (temporary redirect)، عندما تستدعي <code>redirect_to</code>. إذا كنت ترغب في استخدام رمز حالة مختلف، ربما 301، أو إعادة توجيه دائمة، فيمكنك استخدام الخيار <code>:status</code>:<syntaxhighlight lang="rails">
=== 2.3.1 الحصول على شيفرة مختلفة لإعادة توجيه الحالة ===
يستخدم ريلز شيفرة الحالة HTTP 302 ، وهي شيفرة إعادة توجيه مؤقتة، عندما تتصل بـ redirect_to. إذا كنت ترغب في استخدام شيفرة حالة مختلفة، ربما 301، أو إعادة توجيه دائمة، فيمكنك استخدام الخيار: status:
 
redirect_to photos_path, status: 301
redirect_to photos_path, status: 301
</syntaxhighlight>تمامًا مثل الخيار <code>:status</code> للتابع <code>render</code>، يقبل الخيار <code>:status</code> في التابع <code>redirect_to</code> تسميات الترويسة [[Ruby/Numeric|الرقمية]] أو [[Ruby/Symbol|الرمزية]].


تمامًا مثل: خيار status للعارض كذلك لـ redirect_to يقبل كل من تعيينات رؤوس رقمية ورمزية للعارض.
==== الفرق بين <code>render</code> و <code>redirect_to</code> ====
 
يعتقد المطورون عديمو الخبرة أحيانًا أنَّ التابع <code>redirect_to</code> هو شيء شبيه بالأمر <code>goto</code>، الذي ينقل التنفيذ من مكان إلى آخر في شيفرة ريلز وهذا خطأ بالتأكيد. تتوقف آنذاك شيفرتك عن العمل وتنتظر طلبًا جديدًا للمتصفح؛ ما يحدث هو فقط أنك أخبرت المتصفح بالطلب الذي يجب أن تقدمه بعد ذلك، عن طريق إرسال رمز الحالة HTTP 302.
=== 2.3.2 الفرق بين العارض و redirect_to ===
يفكر مطورو البرامج قليل الخبرة أحيانًا في redirect_to كنوع من أوامر goto، وينقلون التنفيذ من مكان إلى آخر في ريلز. هذا خطأ. تتوقف شيفرتك عن العمل وتنتظر طلبًا جديدًا للمتصفح. ما يحدث هو فقط أنك أخبرت المتصفح بالطلب الذي يجب أن تقدمه بعد ذلك، عن طريق إرسال شيفرة حالة HTTP 302.
 
فكر في هذه الأحداث لمعرفة الفرق:


فكر في الإجراءين التاليين لمعرفة الفرق:<syntaxhighlight lang="rails">
def index
def index
 
  @books = Book.all
 @books = Book.all
 
end
end
 
def show
def show
 
  @book = Book.find_by(id: params[:id])
 @book = Book.find_by(id: params[:id])
  if @book.nil?
 
    render action: "index"
 if @book.nil?
  end
 
   render action: "index"
 
 end
 
end
end
 
</syntaxhighlight>مع الشيفرة في هذا النموذج، من المحتمل أن يكون هناك مشكلة إذا كان المتغير <code>book@</code> فارغًا. تذكر أن <code>render :action</code> لا يُشغِّل أي شيفرة في الإجراء المستهدف، لذلك لن يقوم أي شيء بإعداد المتغير <code>books@</code> الذي قد يتطلبه العرض <code>index</code> على الأرجح. إحدى طرق حل هذه المشكلة هي إعادة التوجيه بدلاً من التصيير:<syntaxhighlight lang="rails">
مع الشيفرة في هذا النموذج، من المحتمل أن يكون هناك مشكلة إذا كان متغير @book فارغًا. تذكر: العارض: لا يُشغِّل الحدث أي شيفرة في الحدث المستهدف، لذلك لن يقوم أي شيء بإعداد متغير @books الذي قد يتطلبه عرض الفهرس على الأرجح. إحدى طرق حل هذه المشكلة هي إعادة التوجيه بدلاً من العرض:
 
def index
def index
 
  @books = Book.all
 @books = Book.all
 
end
end
 
def show
def show
 
  @book = Book.find_by(id: params[:id])
 @book = Book.find_by(id: params[:id])
  if @book.nil?
 
    redirect_to action: :index
 if @book.nil?
  end
 
   redirect_to action: :index
 
 end
 
end
end
</syntaxhighlight>باستخدام هذه الشيفرة، سيقدم المتصفح طلبًا جديدًا للصفحة index، وستُشغَّل الشيفرة في التابع <code>index</code>، وسيكون كل شيء على ما يرام.


باستخدام هذه الشيفرة، سيقدم المتصفح طلبًا جديدًا لصفحة الفهرس، وستُشغَّل الشيفرة في دالة الفهرسة، وستكون جميعها جيدة.
الجانب السلبي الوحيد لهذه الشيفرة هو أنه يتطلب رحلة ذهابًا وإيابًا إلى المتصفح: طَلَبَ المتصفح الإجراء <code>show</code> مع /books/1، فوجد المتحكم أنه لا توجد كتب، لذلك يرسل المتحكم استجابة لإعادة التوجيه بالرمز ‎302 إلى المتصفح لإخباره بالذهاب إلى /books/؛ يمتثل المتصفح ويرسل طلبًا جديدًا مرةً أخرى إلى المتحكم يطلب فيه الإجراء <code>index</code>، ثم يحصل المتحكم على جميع الكتب من قاعدة البيانات ويصيِّر القالب <code>index</code>، ويعيد إرساله إلى المتصفح الذي يعرضه على شاشتك.
 
الجانب السلبي الوحيد لهذه الشيفرة هو أنه يتطلب رحلة ذهابًا وإيابًا إلى المستعرض: طَلَبَ المستعرض الحدث المعروض مع /books /1، ويجد المتحكم أنه لا توجد كتب، لذلك يرسل المتحكم 302 استجابة لإعادة التوجيه إلى المتصفح لإخباره بالذهاب إلى /books/ ، يمتثل المتصفح ويرسل طلب جديد مرة أخرى إلى المتحكم يطلب الآن إجراء الفهرس، ثم يحصل المتحكم على جميع الكتب من قاعدة البيانات ويعرض قالب الفهرس، وترسله إلى المتصفح الذي يعرضها على شاشتك.
 
في تطبيق صغير، قد لا يمثل هذا الإختفاء الإضافي مشكلة، إلا أنه أمر يجب التفكير فيه إذا كان وقت الاستجابة مصدر قلق. يمكننا أن نوضح طريقة واحدة للتعامل مع هذا مع مثال مفتعل:


في تطبيق صغير، قد لا يمثل وقت التأخير المضاف في هذه الحالة مشكلةً، إلا أنه أمر يجب التفكير فيه إذا كان وقت الاستجابة مصدر قلق. يمكننا أن نوضح طريقةً واحدةً للتعامل مع هذا الأمر بالشكل التالي:<syntaxhighlight lang="rails">
def index
def index
 
  @books = Book.all
 @books = Book.all
 
end
end
 
def show
def show
 
  @book = Book.find_by(id: params[:id])
 @book = Book.find_by(id: params[:id])
  if @book.nil?
 
    @books = Book.all
 if @book.nil?
    flash.now[:alert] = "Your book was not found"
 
    render "index"
   @books = Book.all
  end
 
   flash.now[:alert] = "Your book was not found"
 
   render "index"
 
 end
 
end
end
</syntaxhighlight>سيكشف هذا عن عدم وجود كتب مع المعرّف المحدد، وينشر (populate) متغير النسخة ‎<code>@books</code> بكافة الكتب في النموذج، ثم يصيِّر القالب index.html.erb مباشرة ويعيده إلى المتصفح برسالة تنبيه (flash alert message) تخبر المستخدم بما قد حدث.


سيكشف هذا عن عدم وجود كتب ذات معرّف محدد، وملء متغير مثيل @books بكافة الكتب في النموذج، ثم عرض قالب index.html.erb مباشرة، وإعادته إلى المتصفح برسالة تنبيه فلاش لتخبر المستخدم بما حدث.
=== استخدام <code>head</code> لإنشاء استجابات من الترويسات فقط ===
 
يمكن استخدام التابع <code>head</code> لإرسال ردود مع ترويسات فقط للمتصفح. يقبل التابع <code>head</code> عددًا أو رمزًا (اطلع على الجدول المرجعي الموجود في قسم [[Rails/layouts and rendering#.D8.A7.D9.84.D8.AE.D9.8A.D8.A7.D8.B1 :status|الخيار <code>:status</code>]]) الذي يمثل رمز حالة HTTP. يفسَر وسيط الخيارات (options argument) على أنه جدول <code>[[Ruby/Hash|Hash]]</code> يحوي أسماء وقيم الترويسة. على سبيل المثال، يمكنك إعادة ترويسة خطأٍ فقط عبر:<syntaxhighlight lang="rails">
== 2.4 استخدام الرأس لإنشاء استجابات للرأس فقط ==
head :bad_request
يمكن استخدام دالة الرأس لإرسال ردود مع رؤوس فقط للمتصفح. تقبل دالة الرأس رقمًا أو رمزًا (انظر الجدول المرجعي) الذي يمثل شيفرة الحالة HTTP. تُفسَر وسيطة الخيارات على أنها تجزئة لأسماء وقيم العناوين. على سبيل المثال، يمكنك إعادة رأس خطأ فقط:
</syntaxhighlight>سُينتج هذا الترويسة التالية:<syntaxhighlight lang="rails">
 
head :bad_request
 
سُينتج هذا العنوانَ التالي:
 
HTTP/1.1 400 Bad Request
HTTP/1.1 400 Bad Request
Connection: close
Connection: close
Date: Sun, 24 Jan 2010 12:15:53 GMT
Date: Sun, 24 Jan 2010 12:15:53 GMT
Transfer-Encoding: chunked
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
X-Runtime: 0.013483
X-Runtime: 0.013483
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache
Cache-Control: no-cache


أو يمكنك استخدام رؤوس HTTP أخرى لنقل معلومات أخرى:
</syntaxhighlight>أو يمكنك استخدام ترويسات HTTP أخرى لنقل معلومات أخرى عبر:<syntaxhighlight lang="rails">
 
head :created, location: photo_path(@photo)
head :created, location: photo_path(@photo)
 
</syntaxhighlight>التي ستنتج:<syntaxhighlight lang="rails">
التي ستنتج:
 
HTTP/1.1 201 Created
HTTP/1.1 201 Created
Connection: close
Connection: close
Date: Sun, 24 Jan 2010 12:16:44 GMT
Date: Sun, 24 Jan 2010 12:16:44 GMT
Transfer-Encoding: chunked
Transfer-Encoding: chunked
Location: /photos/1
Location: /photos/1
Content-Type: text/html; charset=utf-8
Content-Type: text/html; charset=utf-8
X-Runtime: 0.083496
X-Runtime: 0.083496
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache
Cache-Control: no-cache
</syntaxhighlight>


= 3 هيكلة الطبقات =
== هيكلة التخطيطات ==
عندما تعرض ريلز العرض كرد، فإنها تقوم بذلك عن طريق دمج العرض مع التخطيط الحالية، باستخدام قواعد البحث عن التخطيط الحالية التي غُطِّيت مسبقًا في هذا الدليل. داخل التخطيط، يمكنك الوصول إلى ثلاثة أدوات للجمع بين أجزاء مختلفة من المخرجات لتشكيل الاستجابة الكلية:
عندما تصيِّر ريلز عرضًا على شكل استجابة، فإنها تقوم بذلك عن طريق دمج العرض مع التخطيط الحالي، باستخدام قواعد البحث عن التخطيط الحالي التي تحدثنا عنها مسبقًا في هذا الدليل. داخل أي تخطيط، يمكنك الوصول إلى ثلاثة أدوات للجمع بين أجزاء مختلفة من المخرجات لتشكيل الاستجابة الكلية:
* وسوم الأصول
* وسوم الأصول
* العائد و content_for
* <code>yield</code> و <code>content_for</code>
* جزئيات
* الجزئيات


== 3.1 مساعدو وسم الأصول ==
=== مساعدو وسم الأصول ===
يوفر مساعدو وسم الأصول دوالًا لتوليد HTML تربط عروضًا بالخلاصات، وملفات الجافا سكريبت، وصحائف الأنماط، والصور، ومقاطع الفيديو، والتسجيلات الصوتية. يوجد ستة مساعدين لوسوم الأصول في ريلز:
يوفر مساعدو وسم الأصول (Asset tag helpers) توابعًا لتوليد شيفرة [[HTML]] تربط عروضًا بتغذية (feed)، وشيفرة جافاسكربت، وأوراق الأنماط، والصور، ومقاطع الفيديو، وتسجيلات الصوت. يوجد ستة مساعدين لوسوم الأصول في ريلز هي:
* auto_discovery_link_tag
* <code>auto_discovery_link_tag</code>
* javascript_include_tag
* <code>javascript_include_tag</code>
* stylesheet_link_tag
* <code>stylesheet_link_tag</code>
* image_tag
* <code>image_tag</code>
* video_tag
* <code>video_tag</code>
* audio_tag
* <code>audio_tag</code>
يمكنك استخدام هذه الوسوم في الطبقات أو طرق عرض أخرى، على الرغم من استخدام auto_discovery_link_tag وjavascript_include_tag وstylesheet_link_tag بشكل شائع في قسم <head> في التخطيط.
يمكنك استخدام هذه الوسوم في التخطيطات أو عروض أخرى، على الرغم من أنَّ <code>auto_discovery_link_tag</code> و <code>javascript_include_tag</code> و <code>stylesheet_link_tag</code> تستخدم بشكل شائع ضمن <code>[[HTML/head|<head>]]</code> في أي تخطيط.


تحذير: لا يتحقق مساعدو وسم الأصول من وجود الأصول في المواقع المحددة، إذ يفترضون ببساطة أنك تعرف ما تفعله وينتجون الرابط.
'''تحذير''': لا يتحقق مساعدو وسم الأصول من وجود الأصول في المواقع المحددة، إذ يفترضون ببساطة أنك تعرف ما تفعله ويولدون الرابط.
 
=== 3.1.1 ربط الخلاصات مع auto_discovery_link_tag ===
ينشئ المساعد auto_discovery_link_tag شيفرة HTML يمكن لمعظم المتصفحات وقارئات الخلاصات استخدامها للكشف عن وجود خلاصات RSS أو Atom أو JSON. إنها تأخذ نوع الرابط (: rss ، أو atom ، أو: json)، أو التجزئة من الخيارات التي تُمَرَّر إلى url_for ، وتجزئة الخيارات للوسم:


==== ربط التغذيات مع المساعد <code>auto_discovery_link_tag</code> ====
ينشئ المساعد <code>auto_discovery_link_tag</code> شيفرة [[HTML]] يمكن لمعظم المتصفحات وقارئات التغذية استخدامها للكشف عن وجود تغذية RSS أو Atom أو JSON. يأخذ المساعد نوع الرابط (<code>‎:rss</code>، أو ‎<code>:atom</code>، أو ‎<code>:json</code>)، وجدول <code>[[Ruby/Hash|Hash]]</code> من الخيارات التي تُمَرَّر إلى <code>url_for</code>، وجدول <code>[[Ruby/Hash|Hash]]</code> من الخيارات للوسم:<syntaxhighlight lang="rails">
<%= auto_discovery_link_tag(:rss, {action: "feed"},
<%= auto_discovery_link_tag(:rss, {action: "feed"},
  {title: "RSS Feed"}) %>
</syntaxhighlight>هناك ثلاثة خيارات متاحة للوسم يمكن استعمالها مع المساعد <code>auto_discovery_link_tag</code> هي:
*<code>:rel</code> تحدد القيمة <code>rel</code> في الرابط. القيمة الافتراضية هي "alternate".
*<code>:type</code> يحدد النوع MIME الواضح. سينشئ ريلز نوع MIME مناسبًا تلقائيًا.
*<code>:title</code> يحدد عنوان الرابط. القيمة الافتراضية هي الأحرف الكبيرة للقيمة <code>:type</code> مثل "ATOM" أو "RSS".


 {title: "RSS Feed"}) %>
==== ربط ملفات جافاسكربت مع <code>javascript_include_tag</code> ====
 
يعيد المساعد <code>javascript_include_tag</code> الوسم [[HTML/script|<code><script></code>]] الخاص بلغة [[HTML]] لكل مصدر معطى.
هناك ثلاثة خيارات متاحة للوسم لـ auto_discovery_link_tag:
* :rel تحدد قيمة rel في الرابط. القيمة الافتراضية هي "alternate".
* :type يحدد نوع MIME الواضح. سينشئ ريلز نوع MIME مناسبًا تلقائيًا.
* :title يحدد عنوان الرابط. القيمة الافتراضية هي الأحرف الكبيرة: نوع القيمة، على سبيل المثال ، "ATOM" أو "RSS".
 
=== 3.1.2 ربط ملفات JavaScript مع javascript_include_tag ===
يعيد المساعد javascript_include_tag وسم script الخاص بلغة HTML لكل مصدر مُقَدَّم.
 
إذا كنت تستخدم ريلز مع تمكين Asset Pipeline، سينشئ هذا المساعد رابطًا إلى /assets/javascripts/ بدلاً من public/javascripts الذي كان مستخدَمًا في الإصدارات السابقة من ريلز. ثم هذا الرابط يُخدَم بواسطةأصول pipeline.


يدخل ملف جافا سكريبت داخل أحد تطبيقات ريلز أو محرك ريلز في أحد المواقع الثلاثة: app/assets ، lib/assets أو vendor/assets. شُرحَت هذه المواقع بالتفصيل في قسم تنظيم الأصول في دليل Pipeline الأصول.
إذا كنت تستخدم ريلز مع تمكين [[Rails/asset pipeline|خط أنابيب الأصول]]، سينشئ هذا المساعد رابطًا إلى /assets/javascripts/ بدلاً من public/javascripts الذي كان مستخدَمًا في الإصدارات السابقة من ريلز. ثم هذا الرابط يُخدَم بواسطة خطا أنابيب الأصول (asset pipeline).


تستطيع تحديد مسار كامل يتعلق بجذر المستند، أو عنوان URL، إذا فضلتَ ذلك. على سبيل المثال، للارتباط بملف JavaScript موجود داخل دليل يسمى javascripts داخل أحد app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:
يوضع ملف جافاسكربت داخل أحد تطبيقات ريلز أو محرك ريلز في أحد المواقع الثلاثة:
* <code>app/assets</code>، أو
* <code>lib/assets</code>، أو
* <code>vendor/assets</code>.
شُرحَت هذه المواقع بالتفصيل في قسم تنظيم الأصول في دليل [[Rails/asset pipeline|خط أنابيب الأصول]].


تستطيع تحديد مسار كامل يتعلق بجذر المستند، أو عنوان URL، إذا أردت ذلك. على سبيل المثال، للارتباط بملف JavaScript موجود داخل مجلد يسمى javascripts داخل app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:<syntaxhighlight lang="html">
<%= javascript_include_tag "main" %>
<%= javascript_include_tag "main" %>
 
</syntaxhighlight>بعد ذلك، سيولد ريلز الوسم <code>[[HTML/script|<script>]]</code> التالي:<syntaxhighlight lang="html">
بعد ذلك، سيصدر ريلز وسم script مثل هذا:
 
<script src='/assets/main.js'></script>
<script src='/assets/main.js'></script>
</syntaxhighlight>ثم يُقدَّم الطلب إلى هذا الأصل بواسطة الجوهرة Sprockets.


ثم يُقدَّم الطلب إلى هذا الأصل بواسطة جوهرة Sprockets.
لتضمين ملفات متعددة مثل app/assets/javascripts/main.js و app/assets/javascripts/columns.js في الوقت نفسه، جرب ما يلي:<syntaxhighlight lang="html">
 
لتضمين ملفات متعددة مثل app/assets/javascripts/main.js و app/assets/javascripts/columns.js في الوقت نفسه:
 
<%= javascript_include_tag "main", "columns" %>
<%= javascript_include_tag "main", "columns" %>
 
</syntaxhighlight>لتضمين app/assets/javascripts/main.js و app/assets/javascripts/photos/columns.js:<syntaxhighlight lang="html">
لتضمين app/assets/javascripts/main.js وapp/assets/javascripts/photos/columns.js:
 
<%= javascript_include_tag "main", "/photos/columns" %>
<%= javascript_include_tag "main", "/photos/columns" %>
</syntaxhighlight>لتضمين <nowiki>http://example.com/main.js</nowiki>:<syntaxhighlight lang="html">
<%= javascript_include_tag "http://example.com/main.js" %>
</syntaxhighlight>


لتضمين <nowiki>http://example.com/main.js</nowiki>:
=== ربط ملفات [[CSS]] باستخدام <code>stylesheet_link_tag</code> ===
 
يُعيد المساعد <code>stylesheet_link_tag</code> الوسم <code>[[HTML/link|<link>]]</code> لكل مصدر معطى.
<%= javascript_include_tag "<nowiki>http://example.com/main.js</nowiki>" %>
 
=== 3.1.3 ربط ملفات CSS باستخدام stylesheet_link_tag ===
يُعيد المساعد stylesheet_link_tag وسم <link> لكل مصدر مُقدَّم.
 
إذا كنت تستخدم ريلز مع تمكين "Asset Pipeline"، فسينشئ هذا المساعد رابطًا إلى /assets/stylesheets/. ثم يُعالَج هذا الرابط بعد ذلك بواسطة جوهرة Sprockets. يمكن تخزين ملف stylesheet في أحد المواقع الثلاثة: app/assets app/assets، أو lib/assets، أو vendor/assets.
 
تستطيع تحديد مسار كامل يتعلق بجذر المستند، أو عنوان URL، على سبيل المثال، للارتباط بملف stylesheet موجود داخل دليل يسمى stylesheets داخل أحد app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:


إذا كنت تستخدم ريلز مع تمكين [[Rails/asset pipeline|خط أنابيب الأصول]]، فسينشئ هذا المساعد رابطًا إلى /assets/stylesheets/ ثم يُعالَج هذا الرابط بعد ذلك بواسطة الجوهرة Sprockets. يمكن تخزين ملف ورقة الأنماط في أحد المواقع الثلاثة:
* app/assets، أو
* lib/assets، أو
* vendor/assets.
تستطيع تحديد مسار كامل نسبةً إلى جذر المستند، أو عنوان URL، على سبيل المثال، للارتباط بملف ورقة أنماط موجود داخل مجلد يسمى stylesheets داخل المجلد app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:<syntaxhighlight lang="html">
<%= stylesheet_link_tag "main" %>
<%= stylesheet_link_tag "main" %>
 
</syntaxhighlight>لتضمين app/assets/stylesheets/main.css و app/assets/stylesheets/columns.css:<syntaxhighlight lang="html">
لتضمين app/assets/stylesheets/main.css و app/assets/stylesheets/columns.css:
 
<%= stylesheet_link_tag "main", "columns" %>
<%= stylesheet_link_tag "main", "columns" %>
 
</syntaxhighlight>لتضمين app/assets/stylesheets/main.css و app/assets/stylesheets/photos/columns.css:<syntaxhighlight lang="html">
لتضمين app/assets/stylesheets/main.css وapp/assets/stylesheets/photos/columns.css:
 
<%= stylesheet_link_tag "main", "photos/columns" %>
<%= stylesheet_link_tag "main", "photos/columns" %>
 
</syntaxhighlight>لتضمين <nowiki>http://example.com/main.css</nowiki>:<syntaxhighlight lang="html">
لتضمين <nowiki>http://example.com/main.css</nowiki>:
<%= stylesheet_link_tag "http://example.com/main.css" %>
 
</syntaxhighlight>بشكل افتراضي، يُنشئ <code>stylesheet_link_tag</code> روابط مع <code>media="screen" rel="stylesheet"‎</code>. يمكنك تجاوز أيَّا من هذه القيم الافتراضية عن طريق تحديد الخيار المناسب (<code>:media</code>، أو ):<syntaxhighlight lang="html">
<%= stylesheet_link_tag "<nowiki>http://example.com/main.css</nowiki>" %>
 
بشكل افتراضي، يُنشئ stylesheet_link_tag روابط مع media= "screen" rel= "stylesheet". يمكنك تجاوز أيَّا من هذه الافتراضات عن طريق تحديد الخيار المناسب (media, :rel:):
 
<%= stylesheet_link_tag "main_print", media: "print" %>
<%= stylesheet_link_tag "main_print", media: "print" %>
</syntaxhighlight>


=== 3.1.4 ربط الصور باستخدام image_tag ===
==== ربط الصور باستخدام <code>image_tag</code> ====
ينشئ المساعد image_tag وسم <img /> إلى الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من public/images.
ينشئ المساعد <code>image_tag</code> الوسم <code>[[HTML/img|<img /‎>]]</code> إلى الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من public/images.
 
تحذير: لاحظ أنه يجب عليك تحديد امتداد الصورة.


'''تحذير''': لاحظ أنه يجب عليك تحديد امتداد الصورة.<syntaxhighlight lang="html">
<%= image_tag "header.png" %>
<%= image_tag "header.png" %>
 
</syntaxhighlight>يمكنك توفير مسار للصورة إذا أردت:<syntaxhighlight lang="html">
يمكنك توفير مسار للصورة إذا أردت:
 
<%= image_tag "icons/delete.gif" %>
<%= image_tag "icons/delete.gif" %>
 
</syntaxhighlight>يمكنك توفير جدول <code>[[Ruby/Hash|Hash]]</code> من خيارات [[HTML]] الإضافية:<syntaxhighlight lang="html">
يمكنك توفير تجزئة من خيارات HTML الإضافية:
 
<%= image_tag "icons/delete.gif", {height: 45} %>
<%= image_tag "icons/delete.gif", {height: 45} %>
 
</syntaxhighlight>يمكنك توفير نص بديل للصورة يُستخدَم إذا أوقف المستخدِم تشغيل الصور في المتصفح. إذا لم تُحدد نص بديل بشكل صريح، فسيُعيَّن افتراضيًا باسم الملف بأحرف كبيرة وبدون اللاحقة. على سبيل المثال، قد تعيد هاتان الصورتان نفس الشيفرة:<syntaxhighlight lang="html">
يمكنك توفير نص بديل للصورة التي ستستخدَم إذا أوقف المستخدِم تشغيل الصور في المتصفح. إذا لم تُحدد نص بديل بشكل صريح، فسيُعيَّن افتراضيًا باسم الملف، تكبير بدون الامتداد. على سبيل المثال، قد تعيد هاتان الصورتان نفس الشيفرة:
 
<%= image_tag "home.gif" %>
<%= image_tag "home.gif" %>
<%= image_tag "home.gif", alt: "Home" %>
<%= image_tag "home.gif", alt: "Home" %>
 
</syntaxhighlight>يمكنك أيضًا تحديد حجم خاص للصورة عبر التنسيق "{width} x {height}":<syntaxhighlight lang="html">
يمكنك أيضًا تحديد وسم حجم خاص بالتنسيق "{width} x {height}":
 
<%= image_tag "home.gif", size: "50x20" %>
<%= image_tag "home.gif", size: "50x20" %>
 
</syntaxhighlight>بالإضافة إلى الخيارات الخاصة المذكورة أعلاه، يمكنك توفير جدول <code>[[Ruby/Hash|Hash]]</code> في النهاية لخيارات HTML القياسية، مثل <code>:class</code>، أو <code>:id</code>، أو <code>:name</code>:<syntaxhighlight lang="html">
بالإضافة إلى الوسومات الخاصة المذكورة أعلاه، يمكنك توفير تجزئة نهائية لخيارات HTML القياسية، مثل: class:، أو id:، أو name:
 
<%= image_tag "home.gif", alt: "Go Home",
<%= image_tag "home.gif", alt: "Go Home",
                          id: "HomeImage",
                          class: "nav_bar" %>
</syntaxhighlight>


                         id: "HomeImage",
==== ربط مقاطع الفيديو مع <code>video_tag</code> ====
 
ينشئ المساعد <code>video_tag</code> الوسم <code>[[HTML/video|<video>]]</code> الذي وفرته HTML5 لتضمين مقاطع الفيديو. بشكل افتراضي، تُحمَّل الملفات الفيديو من المجلد public/videos.<syntaxhighlight lang="html">
                         class: "nav_bar" %>
 
=== 3.1.5 ربط مقاطع الفيديو مع video_tag ===
ينشئ المساعد video_tag وسم HTML5 <video> على الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من public/videos.
 
<%= video_tag "movie.ogg" %>
<%= video_tag "movie.ogg" %>
 
</syntaxhighlight>يُنتِج:<syntaxhighlight lang="html">
يُنتِج
 
<video src="/videos/movie.ogg" />
<video src="/videos/movie.ogg" />
</syntaxhighlight>مثل <code>image_tag</code>، يمكنك توفير مسار، إما مطلق، أو نسبي إلى المجلد public/videos. بالإضافة إلى ذلك، يمكنك تحديد الحجم عبر التنسيق "‎#{width}x#{height‎}‎" تمامًا مثل <code>image_tag</code>. يمكن أن تحتوي [[HTML/video|وسوم الفيديو]] أيضًا على أي من خيارات [[HTML]] المحددة في النهاية (مثل الخيار <code>:class</code>، أو <code>:id</code>، أو <code>:name</code>).


مثل image_tag يمكنك توفير مسار ، إما مطلق، أو يناسب إلى الدليل public/videos. بالإضافة إلى ذلك، يمكنك تحديد خيار الحجم: "#{width}x#{height}" تمامًا مثل image_tag. يمكن أن تحتوي وسومات الفيديو أيضًا على أي من خيارات HTML المحددة في النهاية (id ، class et al).
يدعم وسم الفيديو أيضًا جميع خيارات <code>[[HTML/video|<video>]]</code> من خلال وضع خيارات HTML هذه ضمن جدول <code>[[Ruby/Hash|Hash]]</code> من ضمنها:
 
* <code>poster: "image_name.png"‎</code>، يوفر صورة لعرضها في واجهة الفيديو قبل بدء تشغيله.
يدعم وسم الفيديو أيضًا جميع خيارات <video> من خلال تجزئة خيارات HTML، شاملًا:
* <code>autoplay: true</code>، يبدأ تشغيل الفيديو عند تحميل الصفحة.
* poster: "image_name.png"، يوفر صورة لوضعها بدلاً من الفيديو قبل بدء تشغيله.
* <code>loop: true</code>، يكرر الفيديو بمجرد انتهاء تشغليه.
* autoplay: true، يبدأ تشغيل الفيديو عند تحميل الصفحة.
* <code>controls: true</code>، يوفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الفيديو.
* loop: true، يكرر الفيديو بمجرد وصوله إلى النهاية.
* <code>autobuffer: true</code>، سيحمِّل الفيديو الملف مسبقًا للمستخدم أثناء تحميل الصفحة.
* controls: true، يوفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الفيديو.
يمكنك أيضًا تحديد عدة مقاطع فيديو لتشغيلها بتمرير مصفوفة من مقاطع الفيديو إلى <code>video_tag</code>:<syntaxhighlight lang="html">
* autobuffer: true، سيحمل الفيديو الملف للمستخدم على الصفحة المحملة.
يمكنك أيضًا تحديد عدة مقاطع فيديو لتشغيلها بتمرير مصفوفة من مقاطع الفيديو إلى video_tag:
 
<%= video_tag ["trailer.ogg", "movie.ogg"] %>
<%= video_tag ["trailer.ogg", "movie.ogg"] %>
 
</syntaxhighlight>هذا سينتج:<syntaxhighlight lang="html">
هذا سينتج:
 
<video>
<video>
 
  <source src="/videos/trailer.ogg">
 <nowiki><source src="/videos/trailer.ogg"></nowiki>
  <source src="/videos/movie.ogg">
 
 <nowiki><source src="/videos/movie.ogg"></nowiki>
 
</video>
</video>
</syntaxhighlight>


=== 3.1.6 ربط الملفات الصوتية مع audio_tag ===
==== ربط الملفات الصوتية مع <code>audio_tag</code> ====
ينشئ المساعد audio_tag وسم <audio>  على الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من public/audios.
ينشئ المساعد <code>audio_tag</code> الوسم <code>[[HTML/audio|<audio>]]</code>  على الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من المجلد public/audios.<syntaxhighlight lang="html">
 
<%= audio_tag "music.mp3" %>
<%= audio_tag "music.mp3" %>
 
</syntaxhighlight>يمكنك توفير مسار للملف الصوتي إذا كنت ترغب بذلك بالشكل:<syntaxhighlight lang="html">
يمكنك توفير مسار للملف الصوتي إذا كنت ترغب:
 
<%= audio_tag "music/first_song.mp3" %>
<%= audio_tag "music/first_song.mp3" %>
</syntaxhighlight>يمكنك أيضًا توفير مجموعة متنوعة من الخيارات، مثل <code>:class</code> و <code>:id</code> ...إلخ.


يمكنك أيضًا توفير مجموعة متنوعة من الخيارات، مثل: class: و id: إلخ.
مثل المساعد <code>video_tag</code>، يحتوي <code>audio_tag</code> على خيارات خاصة هي:
 
* <code>autoplay: true</code>، يبدأ تشغيل الصوت عند تحميل الصفحة.
مثل video_tag، يحتوي audio_tag على خيارات خاصة:
* <code>controls: true</code>، يوفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الصوت.
* autoplay: true، تبدأ تشغيل الصوت عند تحميل الصفحة
* <code>autobuffer: true</code>، سيحمل ملف الصوت الملف للمستخدم أثناء تحميل الصفحة.
* controls: true، توفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الصوت.
* autobuffer: true، سيحمل ملف الصوت الملف للمستخدم على الصفحة المحملة..
 
== 3.2 فهم yield ==
في سياق التخطيط، يحدد yield قسمًا حيث يجب إدراج المحتوى من العرض. تتمثل أبسط طريقة لاستخدام هذا في الحصول على yield واحد تُدرَج فيه محتويات العرض التي تعرَض حاليًا:


=== فهم <code>yield</code> ===
في سياق أي تخطيط، يعرِّف <code>yield</code> قسمًا حيث يجب إدراج المحتوى من العرض. تتمثل أبسط طريقة لاستخدام هذا في الحصول على <code>yield</code> واحدٍ يُدرَج فيه محتويات العرض قيد التصيير حاليًا:<syntaxhighlight lang="html">
<html>
<html>
 
  <head>
 <head>
  </head>
 
  <body>
 </head>
  <%= yield %>
 
  </body>
 <body>
 
 <%= yield %>
 
 </body>
 
</html>
</html>
 
</syntaxhighlight>يمكنك أيضًا استعمال <code>yield</code> أكثر من مرة ضمن التخطيط:<syntaxhighlight lang="html">
يمكنك أيضًا إنشاء تخطيط بمناطق عائد متعددة:
 
<html>
<html>
 
  <head>
 <head>
  <%= yield :head %>
 
  </head>
 <%= yield :head %>
  <body>
 
  <%= yield %>
 </head>
  </body>
 
 <body>
 
 <%= yield %>
 
 </body>
 
</html>
</html>
</syntaxhighlight>سيصيَّر دائمًا الجسم الرئيسي في <code>yield</code> غير المسمى. لتصيير محتوى إلى <code>yield</code> محدد، تستطيع استخدم التابع <code>content_for</code>.


سيظهر دائمًا الجسم الرئيسي في yieldغير المسمى. لعرض محتوى إلى yieldمحدد، تستطيع استخدم دالة content_for.
=== استخدام التابع <code>content_for</code> ===
 
يسمح لك التابع <code>content_for</code> بإدراج محتوى في كتلة <code>yield</code> محددة في تخطيطك. على سبيل المثال، قد يعمل هذا العرض مع التخطيط التي شاهدته للتو:<syntaxhighlight lang="html">
== 3.3 استخدام طريقة content_for ==
تسمح لك طريقة content_for بإدراج محتوى في كتلة yield المحددة في طبقتك. على سبيل المثال، قد يعمل هذا العرض مع التخطيط التي شاهدتها للتو:
 
<% content_for :head do %>
<% content_for :head do %>
 
  <title>A simple page</title>
 <title>A simple page</title>
 
<% end %>
<% end %>
 
<nowiki><p>Hello, ريلز!</p></nowiki>
<p>Hello, Rails!</p>
 
</syntaxhighlight>ستكون نتيجة تصيير هذه الصفحة في التخطيط المعطى هي شيفرة [[HTML]] التالية:<syntaxhighlight lang="html">
ستكون نتيجة عرض هذه الصفحة في التخطيط الذي عُرِضَ هي شيفرة الـ HTML هذه:
 
<html>
<html>
 
  <head>
 <head>
  <title>A simple page</title>
 
  </head>
 <title>A simple page</title>
  <body>
 
  <p>Hello, Rails!</p>
 </head>
  </body>
 
 <body>
 
 <nowiki><p>Hello, ريلز!</p></nowiki>
 
 </body>
 
</html>
</html>
</syntaxhighlight>التابع <code>content_for</code> مفيد للغاية عندما يحتوي تخطيطك على مناطق مميزة مثل الأقسام الجانبية (sidebars) والتذييلات التي يجب أن تُدرَج كتلها الخاصة بها. كما يفيد أيضًا في إدراج الوسوم التي تحمّل ملفات [[JavaScript|جافاسكربت]] أو ملفات [[CSS]] الخاصة بالصفحة في رأس تخطيط آخر عام.


طريقة content_for مفيدة للغاية عندما تحتوي طبقتك على مناطق مميزة مثل الأشرطة الجانبية والتذييلات التي يجب أن تُدرَج كتلها الخاصة بها. كما تفيد أيضًا في إدراج الوسوم التي تحمّل ملفات جافا سكريبت أو ملفات css الخاصة بالصفحة في رأس تخطيط آخر عام.
=== استخدام الجزئيات ===
 
القوالب الجزئية - عادة ما تسمى "الجزئيات" (partials) - هي أداة أخرى لتجزئة عملية التصيير إلى أجزاء أكثر قابلية للإدارة. باستخدام جزئية، يمكنك نقل الشيفرة لتصيير جزء معين من الاستجابة لملفها الخاص.
== 3.4 استخدام الجزئيات ==
النماذج الجزئية - عادة ما تسمى "الجزئيات" - هي أداة أخرى لتجزئة عملية العرض إلى أجزاء أكثر قابلية للإدارة. باستخدام جزئية، يمكنك نقل الشيفرة لعرض جزء معين من الاستجابة لملفها الخاص.
 
=== 3.4.1 تسمية الجزئيات ===
لعرض جزء كجزء من عرض، فإنك تستخدم العارض في العرض:


==== تسمية الجزئيات ====
لتصيير جزئية كجزء من عرض، فاستخدم التابع <code>render</code> في العرض:<syntaxhighlight lang="html">
<%= render "menu" %>
<%= render "menu" %>
 
</syntaxhighlight>سيؤدي ذلك إلى تصيير ملف يدعى ‎_menu.html.erb في تلك النقطة داخل العرض قيد التصيير. لاحظ الشرطة السفلية البادئة لاسم الملف: تبدأ أسماء الجزئيات بشرطة سفلية لتمييزها عن العروض العادية، رغم أنه يشار إليها بدون الشرطة السفلية. هذا صحيح حتى عند سحب جزء من مجلد آخر:<syntaxhighlight lang="html">
سيؤدي ذلك إلى عرض ملف named _menu.html.erb في تلك النقطة داخل العرض الذي يُعرض. لاحظ حرف الشرطة السفلية البادئة: تُسمَّى الجزئيات باستخدام شرطة سفلية بادئة لتمييزها عن العروض العادية، حتى لو أشير إليها بدون الشرطة السفلية. هذا صحيح حتى عند سحب جزء من مجلد آخر:
 
<%= render "shared/menu" %>
<%= render "shared/menu" %>
</syntaxhighlight>ستسحب (pull) هذه الشيفرة في الجزئية من app/views/shared/_menu.html.erb.


سيسحب هذا الرمز في الجزئية من app/views/shared/_menu.html.erb.
==== استخدام الجزئيات لتبسيط العروض ====
 
إحدى الطرق لاستخدام الجزئيات هي معاملتهم بشكل مكافئ للمهام الفرعية (subroutines): كطريقة لنقل التفاصيل خارج العرض بحيث يمكنك التحكم بزمام الأمور بسهولة أكبر. على سبيل المثال، قد يكون لديك عرض يبدو كالتالي:<syntaxhighlight lang="html">
=== 3.4.2 استخدام Partials لتبسيط العروض ===
إحدى الطرق لاستخدام الجزئيات هي معاملتهم على أنها مكافئات الوظائف الفرعية: كطريقة لنقل التفاصيل خارج العرض بحيث يمكنك فهم ما يجري بسهولة أكبر. على سبيل المثال، قد يكون لديك عرض يبدو كالتالي:
 
<%= render "shared/ad_banner" %>
<%= render "shared/ad_banner" %>
 
<h1>Products</h1>
<nowiki><h1>Products</h1></nowiki>
<p>Here are a few of our fine products:</p>
 
<nowiki><p>Here are a few of our fine products:</p></nowiki>
 
...
...
<%= render "shared/footer" %>
<%= render "shared/footer" %>
</syntaxhighlight>هنا، يمكن أن تحتوي كل من الجزئية ‎_ad_banner.html.erb و ‎_footer.html.erb على محتوى مشترك من قبل العديد من الصفحات في تطبيقك. لست بحاجة إلى الاطلاع على تفاصيل هذه الأقسام عند التركيز على صفحة معينة.


هنا، يمكن أن يحتوي كل من _ad_banner.html.erb و _footer.html.erb على محتوى مشترك من قبل العديد من الصفحات في تطبيقك. لست بحاجة إلى الاطلاع على تفاصيل هذه الأقسام عند التركيز على صفحة معينة.
كما هو موضح في الأقسام السابقة من هذا الدليل، تعدُّ <code>yield</code> أداةً قويةً جدًا لتنظيف تخطيطاتك. ضع في اعتبارك أنها شيفرة [[Ruby|روبي]] صرفة، لذلك يمكنك استخدامها في كل مكان تقريبا. على سبيل المثال، يمكننا استخدام الجزئيات لتقليل تعريفات تخطيط نموذج لعدة مصادر متشابهة:
 
* الملف users/index.html.erb
كما هو موضح في الأقسام السابقة من هذا الدليل، تعد yield أداةً قويةً جدًا لتنظيف طبقاتك. ضع في اعتبارك أنه روبي نقي، لذلك يمكنك استخدامه في كل مكان تقريبا. على سبيل المثال، يمكننا استخدام DRY لتعريفات نموذج تخطيط لعدة مصادر متشابهة:
<syntaxhighlight lang="html">
* users/index.html.erb
<%= render "shared/search_filters", search: @q do |f| %>
<%= render "shared/search_filters", search: @q do |f| %>
 
  <p>
 <nowiki><p></nowiki>
    Name contains: <%= f.text_field :name_contains %>
 
  </p>
   Name contains: <%= f.text_field :name_contains %>
 
 <nowiki></p></nowiki>
 
<% end %>
<% end %>
* roles/index.html.erb
</syntaxhighlight>
* الملف roles/index.html.erb
<syntaxhighlight lang="html">
<%= render "shared/search_filters", search: @q do |f| %>
<%= render "shared/search_filters", search: @q do |f| %>
 
  <p>
 <nowiki><p></nowiki>
    Title contains: <%= f.text_field :title_contains %>
 
  </p>
   Title contains: <%= f.text_field :title_contains %>
 
 <nowiki></p></nowiki>
 
<% end %>
<% end %>
* shared/_search_filters.html.erb
</syntaxhighlight>
* الملف shared/_search_filters.html.erb
<syntaxhighlight lang="html">
<%= form_for(search) do |f| %>
<%= form_for(search) do |f| %>
 
  <h1>Search form:</h1>
 <nowiki><h1>Search form:</h1></nowiki>
  <fieldset>
 
    <%= yield f %>
 <fieldset>
  </fieldset>
 
  <p>
   <%= yield f %>
    <%= f.submit "Search" %>
 
  </p>
 </fieldset>
 
 <nowiki><p></nowiki>
 
   <%= f.submit "Search" %>
 
 <nowiki></p></nowiki>
 
<% end %>
<% end %>
</syntaxhighlight>بالنسبة للمحتوى الذي جرى مشاركته بين جميع الصفحات في تطبيقك، يمكنك استخدام الجزئيات مباشرة من التخطيطات.


بالنسبة للمحتوى الذي شُورِك بين جميع الصفحات في تطبيقك، يمكنك استخدام الجزئيات مباشرة من الطبقات.
==== التخطيطات الجزئية ====
 
بإمكان الجزئية استخدام ملف تخطيط خاص بها فقط، تمامًا كما يمكن للعرض استخدام تخطيط محدد خاص به. على سبيل المثال، يمكنك استدعاء جزئية بالشكل التالي:<syntaxhighlight lang="html">
=== 3.4.3 الطبقات الجزئية ===
بإمكان الجزء استخدام ملف طبقته، تمامًا كما يمكن للعرض استخدام التخطيط. على سبيل المثال، يمكنك الاتصال بجزء هكذا:
 
<%= render partial: "link_area", layout: "graybar" %>
<%= render partial: "link_area", layout: "graybar" %>
</syntaxhighlight>سيبحث هذا عن جزئية اسمها ‎_link_area.html.erb ويصيِّرها باستخدام التخطيط ‎_graybar.html.erb. لاحظ أن التخطيط الخاص بالجزئيات يتبع نفس نمط تسمية الجزئيات نفسها (البدء بشرطة سفلية)، ويوضع في نفس المجلد مع الجزئية التي ينتمي إليها (وليس في مجلد التخطيطات الرئيسي).


سيبحث هذا عن جزئية اسمها _link_area.html.erb ويعرضها باستخدام layout _graybar.html.erb. لاحظ أن الطبقات الخاصة بالجزئيات تتبع نفس التسمية بالشرطة السفلية كتسمية جزئية منتظمة، وتوضع في نفس المجلد مع الجزئية التي تنتمي إليها (وليس في مجلد الطبقات الرئيسي).
لاحظ أيضًا التحديد <code>:‎partial</code> الصريح هذا مطلوب عند تمرير خيارات إضافية مثل الخيار <code>:layout</code>.
 
لاحظ أيضًا هذا التحديد الصريح: partial مطلوب عند تمرير خيارات إضافية مثل:layout.
 
=== 3.4.4 تمرير المتغيرات المحلية ===
يمكنك أيضًا تمرير المتغيرات المحلية إلى الجزئيات، مما يجعلها أكثر قوة ومرونة. على سبيل المثال، يمكنك استخدام هذه التقنية لتقليل التكرار بين الصفحات الجديدة والتعديل، مع الاحتفاظ بقليل من المحتوى المميز:
* new.html.erb
<nowiki><h1>New zone</h1></nowiki>


==== تمرير متغيرات محلية ====
يمكنك أيضًا تمرير متغيرات محلية إلى الجزئيات، مما يجعلها أكثر قوة ومرونة. على سبيل المثال، يمكنك استخدام هذه التقنية لتقليل التكرار بين الصفحات الجديدة والمعدلَّة، مع الاحتفاظ بقليل من المحتوى المميز:
* الملف new.html.erb
<syntaxhighlight lang="html">
<h1>New zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>
<%= render partial: "form", locals: {zone: @zone} %>
* edit.html.erb
</syntaxhighlight>
<nowiki><h1>Editing zone</h1></nowiki>
* الملف edit.html.erb
 
<syntaxhighlight lang="html">
<h1>Editing zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>
<%= render partial: "form", locals: {zone: @zone} %>
* form.html.erb_
</syntaxhighlight>
* الملف form.html.erb_
<syntaxhighlight lang="html">
<%= form_for(zone) do |f| %>
<%= form_for(zone) do |f| %>
 
  <p>
 <nowiki><p></nowiki>
    <b>Zone name</b><br>
 
    <%= f.text_field :name %>
   <nowiki><b>Zone name</b></nowiki><nowiki><br></nowiki>
  </p>
 
  <p>
   <%= f.text_field :name %>
    <%= f.submit %>
 
  </p>
 <nowiki></p></nowiki>
 
 <nowiki><p></nowiki>
 
   <%= f.submit %>
 
 <nowiki></p></nowiki>
 
<% end %>
<% end %>
</syntaxhighlight>رغم أن الجزئية نفسها ستصيِّر في كلا العرضين، فسيعيد مساعد إرسال [[Rails/action view|Action View]] القيمة "Create Zone" للإجراء <code>new</code> والقيمة "Update Zone" للإجراء <code>edit</code>.


على الرغم من أن الجزئية نفسها ستُعرضَ في كل من عرضين، فسيعيد مساعد إرسال عرض الحدث "Create Zone" للحدث الجديد و "Update Zone" لحدث التعديل.
لتمرير متغير محلي إلى جزئية في حالات محددة فقط، استخدم <code>local_assigns</code>.
 
* الملف index.html.erb
لتمرير متغير محلي إلى جزئية في حالات محددة فقط، استخدم local_assigns.
<syntaxhighlight lang="html">
* show.html.erb
<%= render user.articles %>
</syntaxhighlight>
* الملف show.html.erb
<syntaxhighlight lang="html">
<%= render article, full: true %>
<%= render article, full: true %>
* article.html.erb_
</syntaxhighlight>
<nowiki><h2><%= article.title %></h2></nowiki>
* الملف article.html.erb_
 
<syntaxhighlight lang="html">
<h2><%= article.title %></h2>
<% if local_assigns[:full] %>
<% if local_assigns[:full] %>
 
  <%= simple_format article.body %>
 <%= simple_format article.body %>
 
<% else %>
<% else %>
 
  <%= truncate article.body %>
 <%= truncate article.body %>
 
<% end %>
<% end %>
</syntaxhighlight>تمكن هذه الطريقة استخدام الجزئية دون الحاجة إلى التصريح عن جميع المتغيرات المحلية.


هذه الطريقة  ممكنة لاستخدام الجزئية دون الحاجة إلى الإعلان عن جميع المتغيرات المحلية.
تحتوي كل جزئية أيضًا على متغير محلي بنفس اسم الجزئية (باستثناء الشرطة السفلية البادئة). يمكنك تمرير كائن إلى هذا المتغير المحلي عبر الخيار <code>:object</code>:<syntaxhighlight lang="html">
 
تحتوي كل جزئية أيضًا على متغير محلي بنفس الاسم مثل جزئية (minus the leading underscore). يمكنك تمرير كائن إلى هذا المتغير المحلي عبر خيار object:
 
<%= render partial: "customer", object: @new_customer %>
<%= render partial: "customer", object: @new_customer %>
</syntaxhighlight>داخل الجزئية <code>customer</code>، سيشير المتغير <code>customer</code> إلى <code>‎@new_customer</code> من العرض الرئيسي.


داخل الجزئية customer، سيشير المتغير customer إلى @new_customer من العرض الرئيسي.
إذا كان لديك نسخةً لنموذج لتصييره إلى جزئية، فيمكنك استخدام صيغة مختصرة بالشكل التالي:<syntaxhighlight lang="html">
 
إذا كان لديك مثيل لنموذج لعرضه جزئيًا، فيمكنك استخدام بنية مختصرة:
 
<%= render @customer %>
<%= render @customer %>
</syntaxhighlight>بافتراض أن متغير النسخة ‎<code>@customer</code> يحتوي على نسخة للنموذج <code>Customer</code>، سيستخدم هذا ‎_customer.html.erb لتصييره ثم سيمرر المتغير المحلي <code>customer</code> إلى الجزئية التي ستشير إلى متغير النسخة ‎<code>@customer</code> في العرض الأصلي.


بافتراض أن متغير المثيل @customer يحتوي على مثال للنموذج Customer، سيستخدم هذا _customer.html.erb لعرضه وسيمرر المتغير المحلي customer إلى الجزئية التي ستشير إلى متغير المثيل @customer في العرض الأصلي.
==== تصيير المجموعات ====
 
الجزئيات مفيدة للغاية في تصيير المجموعات. عند تمريرك مجموعة إلى جزئية عبر الخيار <code>:collection</code>، ستُدرَج الجزئية مرة واحدة لكل عضو في المجموعة:
=== 3.4.5 مجموعات العرض ===
* الملف index.html.erb
الجزئيات مفيدة للغاية في عرض المجموعات. عند تمريرك مجموعة إلى جزئية عبر خيار :collection، ستُدرَج الجزئية مرة واحدة لكل عضو في المجموعة:
<syntaxhighlight lang="html">
* index.html.erb
<h1>Products</h1>
<nowiki><h1>Products</h1></nowiki>
 
<%= render partial: "product", collection: @products %>
<%= render partial: "product", collection: @products %>
* product.html.erb_
<nowiki><p>Product Name: <%= product.name %></p></nowiki>


عندما تُستدعى جزئية ما مع مجموعة متعددة، فإن المثيلات الفردية للجزئية يكون لها حق الوصول إلى عضو المجموعة التي تُعرَض عبر متغير مسمى بعد الجزئية. في هذه الحالة، الجزئية هي product_، وضمن الجزئية  product_، يمكنك الإشارة إلى المنتج للحصول على المثيل الذي يُعرَض.
</syntaxhighlight>
 
* الملف product.html.erb_
هناك أيضا اختزال لهذا. بافتراض أن @products عبارة عن مجموعة من مثيلات منتج، يمكنك ببساطة كتابة هذا في index.html.erb للحصول على النتيجة نفسها:
<syntaxhighlight lang="html">
 
<p>Product Name: <%= product.name %></p>
<nowiki><h1>Products</h1></nowiki>
</syntaxhighlight>عندما تُستدعى جزئية ما مع مجموعة متعددة، فإن النسخ الفردية للجزئية يكون لها حق الوصول إلى عضو المجموعة الذي يجري تصييره عبر متغير مسمى بعد الجزئية. في هذه الحالة، الجزئية هي <code>product_</code>، وضمن الجزئية <code>product_</code>، يمكنك الإشارة إلى <code>product</code> للحصول على النسخة التي يجري تصييرها.


هناك أيضا اختزال لهذه العملية. بافتراض أن ‎<code>@products</code> عبارة عن مجموعة من نسخ من <code>product</code>، يمكنك ببساطة كتابة هذا في الملف index.html.erb للحصول على النتيجة نفسها:<syntaxhighlight lang="html">
<h1>Products</h1>
<%= render @products %>
<%= render @products %>
 
</syntaxhighlight>يحدد ريلز اسم الجزئية المراد استخدامها من خلال النظر إلى اسم النموذج في المجموعة. في الواقع، يمكنك حتى إنشاء مجموعة غير متجانسة وعرضها بهذه الطريقة، وسوف يختار ريلز الجزئية المناسبة لكل عضو في المجموعة:
يحدد ريلز اسم الجزئية المراد استخدامها من خلال النظر إلى اسم الطراز في المجموعة. في الواقع، يمكنك حتى إنشاء مجموعة غير متجانسة وعرضها بهذه الطريقة، وسوف يختار ريلز الجزئية المناسبة لكل عضو في المجموعة:
* الملف index.html.erb
* index.html.erb
<syntaxhighlight lang="html">
<nowiki><h1>Contacts</h1></nowiki>
<h1>Contacts</h1>
 
<%= render [customer1, employee1, customer2, employee2] %>
<%= render [customer1, employee1, customer2, employee2] %>
* customers/_customer.html.erb
</syntaxhighlight>
<nowiki><p>Customer: <%= customer.name %></p></nowiki>
* الملف customers/_customer.html.erb
* employees/_employee.html.erb
<syntaxhighlight lang="html">
<nowiki><p>Employee: <%= employee.name %></p></nowiki>
<p>Customer: <%= customer.name %></p>
 
</syntaxhighlight>
في هذه الحالة، سيستخدم ريلز جزئيات customer أو جزئيات employee حسب الاقتضاء لكل عضو في المجموعة.
* الملف employees/_employee.html.erb
 
<syntaxhighlight lang="html">
إذا كانت المجموعة فارغة، سيعيد العارض فراغًا، لذلك يجب أن يكون من السهل تقديم محتوى بديل.
<p>Employee: <%= employee.name %></p>
 
</syntaxhighlight>في هذه الحالة، سيستخدم ريلز الجزئية <code>customer</code> أو الجزئية <code>employee</code> بما بناسب كل عضو في المجموعة.
<nowiki><h1>Products</h1></nowiki>


إذا كانت المجموعة فارغة، سيعيد التابع render القيمة <code>nil</code>، لذلك يجب أن يكون من السهل توفير محتوى بديل.<syntaxhighlight lang="html">
<h1>Products</h1>
<%= render(@products) || "There are no products available." %>
<%= render(@products) || "There are no products available." %>
</syntaxhighlight>


=== 3.4.6 المتغيرات المحلية ===
==== المتغيرات المحلية ====
لاستخدام اسم متغير محلي مخصص داخل الجزئية، حدد الخيار :as في الاستدعاء إلى الجزئية:
لاستخدام اسم متغير محلي مخصص داخل الجزئية، حدد الخيار <code>:as</code> أثناء استدعاء الجزئية:<syntaxhighlight lang="html">
 
<%= render partial: "product", collection: @products, as: :item %>
<%= render partial: "product", collection: @products, as: :item %>
</syntaxhighlight>باستخدام هذا التغيير، يمكنك الوصول إلى نسخة للمجموعة ‎<code>@products</code> باعتباره المتغير المحلي <code>item</code> داخل الجزئية.
 
باستخدام هذا التغيير، يمكنك الوصول إلى مثيل لمجموعة @products باعتباره العنصر المتغير المحلي داخل الجزئية.
 
يمكنك أيضًا تمرير متغيرات محلية عشوائية إلى أي جزئية تعرضها مع خيار المحليين:{} :


يمكنك أيضًا تمرير متغيرات محلية عشوائية إلى أي جزئية تصييرها مع الخيار المحليين <code>locals: {}‎</code>:<syntaxhighlight lang="html">
<%= render partial: "product", collection: @products,
<%= render partial: "product", collection: @products,
          as: :item, locals: {title: "Products Page"} %>
</syntaxhighlight>في هذه الحالة، ستحصل الجزئية على حق الوصول إلى المتغير المحلي <code>title</code> ذي القيمة "Products Page".


          as: :item, locals: {title: "Products Page"} %>
'''تنويه''': يجعل ريلز أيضًا متغير عداد (counter variable) متاحًا داخل جزئية تستدعى بواسطة المجموعة، يسمى بعد عنوان الجزئية متبوعًا بالعبارة <code>counter_</code>. على سبيل المثال، عند عرض مجموعة باسم <code>products@</code>، يمكن للجزئية product.html.erb_ الوصول إلى المتغير <code>product_counter</code> الذي يفهرس عدد العناصر التي صُيِّرَت داخل العرض المرفق.
 
في هذه الحالة، ستحصل الجزئية على حق الوصول إلى عنوان متغير محلي بقيمة "Products Page".


يجعل ريلز أيضًا متغير عداد متاحًا داخل جزئية تستدعى بواسطة المجموعة، يسمى بعد عنوان الجزئية متبوعًا بـ counter_. على سبيل المثال، عند عرض مجموعة products@، يمكن للجزئية product.html.erb_ الوصول إلى المتغير product_counter الذي يفهرس عدد المرات التي عُرضَ فيها داخل العرض المرفق.
يمكنك أيضًا تحديد جزئية ثانية لتصييرها بين نسخ الجزئية الرئيسية باستخدام الخيار <code>:spacer_template</code>.


يمكنك أيضًا تحديد جزئية ثانية لعرضها بين مثيلات الجزئية الرئيسية باستخدام الخيار spacer_template:
==== قوالب الفصل ====
 
<syntaxhighlight lang="html">
=== 3.4.7 قوالب الفاصل ===
<%= render partial: @products, spacer_template: "product_ruler" %>
<%= render partial: @products, spacer_template: "product_ruler" %>
</syntaxhighlight>ستصيِّر ريلز الجزئية <code>product_ruler_</code> (دون تمرير بيانات إليها) بين كل زوج من الجزئيات <code>product_</code>.


سيعرض rails ال  product_ruler_ الجزئي (دون تمرير بيانات إليه) بين كل زوج من جزئيات product_.
==== مجموعة التخطيطات الجزئية ====
 
عند تصيير المجموعات، يمكن أيضًا استخدام الخيار <code>:layout</code>:<syntaxhighlight lang="html">
=== 3.4.8 مجموعة الطبقات الجزئية ===
عند عرض المجموعات، يمكن أيضًا استخدام خيار layout:
 
<%= render partial: "product", collection: @products, layout: "special_layout" %>
<%= render partial: "product", collection: @products, layout: "special_layout" %>
</syntaxhighlight>سيُصيَّر التخطيط مع الجزئية لكل عنصر في المجموعة. سيتوفر المتغيران <code>object</code> و <code>object_counter</code> الحاليان في التخطيط أيضًا، تمامًا كما هما داخل الجزئية.


ستُعرَض التخطيط مع الجزئية لكل عنصر في المجموعة. سيتوفر المتغيران الكائن و object_counter الحاليان في التخطيط أيضًا، تمامًا كما هما داخل الجزئية.
=== استخدام التخطيطات المتداخلة ===
قد تجد أن تطبيقك يتطلب تخطيطًا يختلف قليلًا عن تخطيط تطبيقك العادي لدعم متحكم معين. بدلًا من تكرار التخطيط الرئيسي وتعديله، يمكنك القيام بذلك باستخدام التخطيطات المتداخلة (nested layouts، تسمى أحيانًا القوالب الفرعية [sub-templates]). هنا مثال:


== 3.5 استخدام الطبقات المتداخلة ==
لنفترض أن لديك التخطيط <code>ApplicationController</code> التالي:
قد تجد أن تطبيقك يتطلب تخطيطً تختلف قليلًا عن تخطيط تطبيقك العادي لدعم متحكم معين. بدلاً من تكرار التخطيط الرئيسيو وتحريرها، يمكنك إنجاز ذلك باستخدام الطبقات المتداخلة (التي تسمى أحيانًا النماذج الفرعية). هنا مثال:
* الملف app/views/layouts/application.html.erb
 
<syntaxhighlight lang="html">
لنفترض أن لديك تخطيط ApplicationController التالية
* app/views/layouts/application.html.erb
<html>
<html>
<head>
<head>
 
  <title><%= @page_title or "Page Title" %></title>
 <title><%= @page_title or "Page Title" %></title>
  <%= stylesheet_link_tag "layout" %>
 
  <style><%= yield :stylesheets %></style>
 <%= stylesheet_link_tag "layout" %>
 
 <style><%= yield :stylesheets %></style>
 
</head>
</head>
<body>
<body>
 
  <div id="top_menu">Top menu items here</div>
 <nowiki><div id="top_menu">Top menu items here</div></nowiki>
  <div id="menu">Menu items here</div>
 
  <div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div>
 <nowiki><div id="menu">Menu items here</div></nowiki>
 
 <nowiki><div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div></nowiki>
 
</body>
</body>
</html>
</html>
 
</syntaxhighlight>في الصفحات المولدة بواسطة <code>NewsController</code>، تريد إخفاء القائمة العلوية وإضافة قائمة يمينية:
على الصفحات التي المُنشئَة بواسطة NewsController، تريد إخفاء القائمة العلوية وإضافة قائمة إلى اليمين:
* الملف app/views/layouts/news.html.erb
* app/views/layouts/news.html.erb
<syntaxhighlight lang="html">
<% content_for :stylesheets do %>
<% content_for :stylesheets do %>
 
  #top_menu {display: none}
 #top_menu {display: none}
  #right_menu {float: right; background-color: yellow; color: black}
 
 #right_menu {float: right; background-color: yellow; color: black}
 
<% end %>
<% end %>
<% content_for :content do %>
<% content_for :content do %>
 
  <div id="right_menu">Right menu items here</div>
 <nowiki><div id="right_menu">Right menu items here</div></nowiki>
  <%= content_for?(:news_content) ? yield(:news_content) : yield %>
 
 <%= content_for?(:news_content) ? yield(:news_content) : yield %>
 
<% end %>
<% end %>
<%= render template: "layouts/application" %>


<%= render template: "layouts/application" %>
</syntaxhighlight>انتهينا! ستَستخدم العروض <code>News</code> التخطيط الجديد، الذي يخفي القائمة العلوية ويضيف قائمة يمينية جديدة في العنصر <code>[[HTML/div|<nowiki><div></nowiki>]]</code> ذي المعرف <code>content</code>.


هذا هو. ستَستخدم عروض الأخبار التخطيط الجديدة، وإخفاء القائمة العلوية وإضافة قائمة جديدة في "div "content.
هناك عدة طرق للحصول على نتائج مشابهة مع أنظمة التخطيط الفرعية المختلفة باستخدام هذه التقنية. لاحظ أنه لا يوجد حد في مستويات التداخل. يمكن استخدام التابع <code>ActionView::render</code> عبر <code>render template: 'layouts/news'‎</code> لتأسيس تخطيط جديدة في التخطيط <code>News</code>. إذا كنت متأكدًا من أنك لن تفرِّع (subtemplate) قالبًا من التخطيط <code>News</code>، فيمكنك تبديل <code>yield</code> مكان <code>content_for?(:news_content) ? yield(:news_content) : yield</code> ببساطة.


هناك عدة طرق للحصول على نتائج مشابهة مع أنظمة التخطيط الفرعية المختلفة باستخدام هذه التقنية. لاحظ أنه لا يوجد حد في مستويات التداخل. يمكن استخدام دالة ActionView::render عبر قالب العرض: 'layouts/news' لتأسيس تخطيط جديدة في تخطيط الأخبار. إذا كنت متأكدًا من أنك لن تدون تخطيط الأخبار، فيمكنك استبدال content_for?(:news_content) ? yield(:news_content) : yield مع yield ببساطة.
== مصادر ==
* [https://guides.rubyonrails.org/layouts_and_rendering.html صفحة Layouts and Rendering in Rails في توثيق Ruby On Rails الرسمي.]

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

يغطي هذا الدليل ميزات التخطيط الأساسية لوحدتي التحكم والعرض. بعد قراءة هذا الدليل، ستتعلم:

  • كيفية استخدام توابع التصيير المختلفة المضمنة ‎في ريلز.
  • كيفية إنشاء تخطيطات (layouts) تحتوي على أقسام محتوى متعددة.
  • كيفية استخدام الأجزاء مع واجهات العرض.
  • كيفية استخدام تخطيطات متداخلة (قوالب فرعية).

نظرة عامة: كيف تتراكب قطع الأحجية معًا

يركز هذا الدليل على التفاعل بين المتحكم والعرض في نمط التصميم Model-View-Controller. كما تعلم، فإنَّ المتحكم مسؤول عن تنظيم العملية الكاملة للتعامل مع الطلب في ريلز، على الرغم من أنه عادة لا يتعامل مع أي شيفرة ثقيلة في النموذج. ولكن بعد ذلك، عندما يحين وقت إرسال رد مرة أخرى إلى المستخدم، يسلم المتحكم بعض الأشياء إلى وحدة العرض. إنه التبادل الذي هو موضوع هذا الدليل.

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

إنشاء الردود

من وجهة نظر المتحكم، هناك ثلاث طرق لإنشاء استجابة HTTP:

  1. استدعاء render لإنشاء استجابة كاملة لإرسالها مرة أخرى إلى المتصفح، أو
  2. استدعاء redirect_to لإرسال شيفرة إعادة التوجيه HTTP إلى المتصفح، أو
  3. استدعاء head لإنشاء استجابة تتكون من ترويسات HTTP فقط لإرسالها مرة أخرى إلى المتصفح.

التصيير افتراضيًا: العرف فوق الضبط في الإجراء

كنت سمعت أن ريلز يعزز العرف (convention) على الضبط (configuration). التصيير الافتراضي هو مثال ممتاز على هذا. بشكل افتراضي، يصيِّر المتحكم في ريلز تلقائيًا العرض بأسماء تتوافق مع المسارات الموجهة الصالحة. مثلًا، إذا كان لديك هذه الشيفرة في الصنف BooksController الخاصة بك:

class BooksController < ApplicationController
end

وما يلي في ملف مساراتك الموجهة:

resources :books

ولديك ملف العرض app/views/books/index.html.erb الذي يحوي:

<h1>Books are coming soon!</h1>

ستصيِّر ريلز العرض app/views/books/index.html.erb عند الانتقال إلى books/ وستشاهد العبارة "Books are coming soon!‎" على شاشتك. ومع ذلك، لا تكون هذه الشاشة مفيدةً إلا قليلًا، لذلك ستُنشئ قريبًا النموذج Book الخاص بك وتضيف الإجراء index إلى BooksController:

class BooksController < ApplicationController
  def index
    @books = Book.all
  end
end

لاحظ أننا لا نملك تصييرًا صريحًا في نهاية إجراء الفهرسة (index) وفقًا لمبدأ "العرف فوق الضبط" (convention over configuration). القاعدة هي أنك إذا لم تصيِّر صراحةً شيئًا في نهاية إجراء المتحكم، فسيبحث ريلز تلقائيًا عن القالب action_name.html.erb في مسار عرض المتحكم ويصيِّره. في هذه الحالة، سيصيِّر ريلز الملف app/views/books/index.html.erb. إذا أردنا إظهار خصائص جميع الكتب في عرضنا، فيمكننا القيام بذلك باستخدام القالب ERB على هذا النحو:

<h1>Listing Books</h1>
 
<table>
  <thead>
    <tr>
      <th>Title</th>
      <th>Content</th>
      <th colspan="3"></th>
    </tr>
  </thead>
 
  <tbody>
    <% @books.each do |book| %>
      <tr>
        <td><%= book.title %></td>
        <td><%= book.content %></td>
        <td><%= link_to "Show", book %></td>
        <td><%= link_to "Edit", edit_book_path(book) %></td>
        <td><%= link_to "Destroy", book, method: :delete, data: { confirm: "Are you sure?" } %></td>
      </tr>
    <% end %>
  </tbody>
</table>
 
<br>
 
<%= link_to "New book", new_book_path %>

ملاحظة: يجرى التصيير الفعلي بواسطة أصناف مشتعبة من النموذج ActionView::Template::Handlers. لا يتعمق هذا الدليل في هذه العملية، ولكن من المهم معرفة أن امتداد الملف في عرضك يتحكم في اختيار معالج القالب.

استخدام التابع render

في معظم الحالات، ينفِّقذ التابع ActionController::Base.render المهام الشاقَّة في تصيير محتوى التطبيق الخاص بك لاستخدامه من قبل المستعرض. هناك مجموعة متنوعة من الطرق لتخصيص سلوك التابع render. يمكنك تصيير العرض الافتراضي لقالب ريلز، أو قالب محدد، أو ملف، أو شيفرة مضمنة، أو لا شيء على الإطلاق. تستطيع تصيير نص أو JSON أو XML. يمكنك تحديد نوع المحتوى أو حالة HTTP للاستجابة المصيَّرة أيضًا.

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

عرض شكل الحدث

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

def update
  @book = Book.find(params[:id])
  if @book.update(book_params)
    redirect_to(@book)
  else
    render "edit"
  end
end

في حالة فشل استدعاء update، يؤدي استدعاء الإجراء update في هذا المتحكم إلى تصيير القالب edit.html.erb المنتمي إلى نفس المتحكم. إذا فَضَّلْتَ ذلك، فيمكنك استخدام رمز بدلًا من سلسلة نصية لتحديد الإجراء المطلوب تصييره:

def update
  @book = Book.find(params[:id])
  if @book.update(book_params)
    redirect_to(@book)
  else
    render :edit
  end
end

تصيير قالب إجراء من متحكم آخر

ماذا لو أردتَ تصيير قالبٍ من متحكم مختلف تمامًا عن ذلك الذي يحتوي على شيفرة الإجراء؟ يمكنك أيضًا فِعل ذلك باستخدام التابع render الذي يقبل المسار الكامل (نسبة إلى app/views) للقالب لتصييره. على سبيل المثال، إذا كنت تُشغِّل شيفرة في المتحكم AdminProductsController توجد في المسار app/controllers/admin، فيمكنك تصيير نتائج الإجراء على قالب في المسار app/views/products بالشكل التالي:

render "products/show"

يعرف ريلز أن هذا العرض ينتمي إلى متحكم مختلف بسبب محرف الخط المائل المضمن في السلسلة النصية. إذا كنت تريد أن تكون صريحًا، فيمكنك استخدام الخيار :template (الذي كان مطلوبًا في ريلز 2.2 والإصدارات الأقدم):

render template: "products/show"

تصيير ملف عشوائي

يمكن للتابع render أيضًا استخدام عرض يقع خارج تطبيقك كليًّا:

render file: "/u/apps/warehouse_app/current/app/views/products/show"

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

ملاحظة: يمكن أن يؤدي استخدام الخيار :file بالتزامن مع إدخالات المستخدمين إلى مشاكل أمنية إذ يمكن للمهاجم استخدام هذا الإجراء للوصول إلى ملفات أمنية حساسة في نظام ملفاتك.

ملاحظة: افتراضيًّا، يصيَّر الملف باستخدام التخطيط الحالي.

فائدة: إذا كنت تُشغَّل ريلز على نظام ويندوز ، يجب استخدام الخيار :file لتصيير ملف، لأن أسماء الملفات في ويندوز لا تملك نفس تنسيق أسماء الملفات في الأنظمة الشبيهة بيونكس.

التغليف

الطرق الثلاث أعلاه للتصيير (تصيير قالب آخر داخل المتحكم، وتصيير قالب داخل متحكم آخر وتصيير ملف عشوائي موجود في نظام الملفات) هي في الواقع حالات مختلفة لنفس الإجراء.

في الواقع، في الصنف BooksController داخل الإجراء update حيث نريد تصيير قالب التعديل (edit template)، إذا لم يُحَدَّث الكتاب (book) بنجاح، فإن جميع إستدعاءات التابع render التالية ستصيِّر القالب edit.html.erb في المسار views/books:

render :edit
render action: :edit
render "edit"
render "edit.html.erb"
render action: "edit"
render action: "edit.html.erb"
render "books/edit"
render "books/edit.html.erb"
render template: "books/edit"
render template: "books/edit.html.erb"
render "/path/to/rails/app/views/books/edit"
render "/path/to/rails/app/views/books/edit.html.erb"
render file: "/path/to/rails/app/views/books/edit"
render file: "/path/to/rails/app/views/books/edit.html.erb"

أيٌّ منهم تستخدمه هو في الحقيقة مسألة أسلوب وتوافق، ولكن القاعدة الأساسية هي استخدام أبسط طريقة منطقية للشيفرة التي تكتبها.

استخدام render مع الخيار :inline

يمكن استخدام التابع render بدون عرض تمامًا، وذلك إذا كنت ترغب في استخدام الخيار :inline لتزويد القالب ERB كجزء من استدعاء الدالة. هذا صحيح تمامًا:

render inline: "<% products.each do |p| %><p><%= p.name %></p><% end %>"

تحذير: نادرًا ما يكون هناك أي سبب وجيه لاستخدام هذا الخيار. مزج القالب ERB مع المتحكم الخاص بك يُغير اتجاه النمط MVC في ريلز وسيجعل من الصعب على مطورين آخرين تتبع منطق المشروع الخاص بك. استخدم طريقة عرض قالب ERB منفصلة بدلًا من ذلك. بشكل افتراضي، يستخدم التصيير المضمَّن القالب ERB. يمكنك إجباره على استخدام القالب Builder بدلًا من ذلك باستخدام الخيار :type:

render inline: "xml.p {'Horrid coding practice!'}", type: :builder

تصيير النصوص

يمكنك إرسال نص مجرد - بدون تنسيق على الإطلاق - إلى المتصفح مرة أخرى باستخدام الخيار :plain مع التابع render:

render plain: "OK"

فائدة: تصيير النص المجرد مفيدٌ للغاية عندما ترد على طلبات Ajax أو خدمة الويب التي تتوقع شيئًا غير شيفرة HTML.

ملاحظة: بشكل افتراضي، إذا استخدمت الخيار :plain، فسيُصيَّر النص بدون استخدام التخطيط الحالي. إذا كنت تريد أن يضع ريلز النص في التخطيط الحالي، فأنت بحاجة إلى إضافة الخيار layout: true واستخدام اللاحقة ‎.text.erb لملف التخطيط.

تصيير شيفرة HTML

يمكنك إرسال سلسلة HTML نصية مرة أخرى إلى المتصفح باستخدام الخيار :html مع التابع render:

render html: helpers.tag.strong('Not Found')

فائدة: هذا الخيار مفيد عند تصيير قطعة صغير من شيفرة HTML. ومع ذلك، قد ترغب في النظر في نقلها إلى ملف قالب إذا كانت الشيفرة معقدةً.

ملاحظة: عند استخدام الخيار :html، ستُهْرَب كيانات HTML إذا لم تكن السلسلة النصية مكونة (composed) مع واجهات برمجة التطبيقات html_safe-aware.

تصيير بيانات بتنسيق JSON

إنَّ JSON هو تنسيق بيانات جافاسكربت تستخدمه العديد من مكتبات Ajax. يحتوي ريلز على دعم مُضمَّن لتحويل الكائنات إلى JSON وتصييرها مجددًا للمتصفح:

render json: @product

تنويه: لا تحتاج إلى استدعاء to_json في الكائن الذي تريد تصييره. إذا كنت تستخدم الخيار :json ، فسيستدعي التابع render التابعَ to_json لك تلقائيًا.

تصيير بيانات بتنسيق XML

يحتوي ريلز أيضًا على دعم مضمن لتحويل الكائنات إلى XML وتصييره مرة أخرى للمستدعِي:

render xml: @product

تنويه: لا تحتاج إلى استدعاء to_xml في الكائن الذي تريد تصييره. إذا كنت تستخدم الخيار :xml، فسوف يستدعي التابع render تلقائيًا to_xml نيابةً عنك.

تصيير شيفرات جافاسكربت الصرفة (VanillaJS)

بإمكان ريلز أن تصيِّر شيفرات جافاسكربت الصرفة (تدعى vanilla JavaScript أو VanillaJS اختصارًا):

render js: "alert('Hello Rails');"

سيرسل هذا السلسلة النصية المعطاة إلى المتصفح باستخدام نوع MIME text/javascript.

تصيير محتوى خام

يمكنك إعادة إرسال محتوى خام إلى المتصفح، دون تعيين أي نوع للمحتوى، باستخدام الخيار :body مع التابع render:

render body: "raw"

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

ملاحظة: ما لم يُستبدَل، فإن ردك المُعاد من استعمال الخيار هذا مع التابع render سيكون من النوع text/plain، لأن هذا هو نوع المحتوى الافتراضي لرد Action Dispatch.

خيارات أخرى

يقبل التابع render عمومًا -إضافةً للخيارات السابقة- خمسةَ خيارات هي:

  1. :content_type
  2. :layout
  3. :location
  4. :status
  5. :formats
الخيار :content_type

بشكل افتراضي، ستخدم (serve) ريلز نتائجَ عملية التصيير مع النوع MIME text/html للمحتوى (أو النوع MIME application/json إذا كنت تستخدم الخيار :json أو النوع MIME application/json إن كنت تستعمل الخيار :xml). هناك أوقات قد ترغب في تغيير هذا، ويمكنك فعل ذلك عن طريق الخيار :content_type بالشكل التالي:

render file: filename, content_type: "application/rss"
الخيار :layout

مع معظم خيارات التابع render، يُعرض المحتوى المصيَّر كجزء من التخطيط الحالي. ستتعلم المزيد حول التخطيطات وكيفية استخدامها لاحقًا في هذا الدليل.

يمكنك استخدام الخيار :layout لإخبار ريلز باستخدام ملف معين كتخطيط للإجراء الحالي:

render layout: "special_layout"

يمكنك أيضًا إخبار ريلز بالتصيير دون تخطيط على الإطلاق:

render layout: false
الخيار :location

يمكنك استخدام الخيار :location لضبط الترويسة HTTP Location:

render xml: photo, location: photo_url(photo)
الخيار :status

سينشئ ريلز تلقائيًا استجابةً باستخدام رمز حالة HTTP الصحيحة (تكون في معظم الحالات هي "200 OK"). يمكنك استخدام الخيار :status لتغيير هذا السلوك:

render status: 500
render status: :forbidden

يفهم ريلز كلًا من رمز الحالة الذي هو عددٌ صحيحٌ والرمز المقابل الموضح في الجدول التالي:

صنف الرد (الاستجابة) رمز حالة HTTP الرمز
Informational 100 ‎:continue
101 ‎:switching_protocols
102 ‎:processing
Success 200 ‎:ok
201 ‎:created
202 ‎:accepted
203 ‎:non_authoritative_information
204 ‎:no_content
205 ‎:reset_content
206 ‎:partial_content
207 ‎:multi_status
208 ‎:already_reported
226 ‎:im_used
Redirection 300 ‎:multiple_choices
301 ‎:moved_permanently
302 ‎:found
303 ‎:see_other
304 ‎:not_modified
305 ‎:use_proxy
307 ‎:temporary_redirect
308 ‎:permanent_redirect
Client Error 400 ‎:bad_request
401 ‎:unauthorized
402 ‎:payment_required
403 ‎:forbidden
404 ‎:not_found
405 ‎:method_not_allowed
406 ‎:not_acceptable
407 ‎:proxy_authentication_required
408 ‎:request_timeout
409 ‎:conflict
410 ‎:gone
411 ‎:length_required
412 ‎:precondition_failed
413 ‎:payload_too_large
414 ‎:uri_too_long
415 ‎:unsupported_media_type
416 ‎:range_not_satisfiable
417 ‎:expectation_failed
421 ‎:misdirected_request
422 ‎:unprocessable_entity
423 ‎:locked
424 ‎:failed_dependency
426 ‎:upgrade_required
428 ‎:precondition_required
429 ‎:too_many_requests
431 ‎:request_header_fields_too_large
451 ‎:unavailable_for_legal_reasons
Server Error 500 ‎:internal_server_error
501 ‎:not_implemented
502 ‎:bad_gateway
503 ‎:service_unavailable
504 ‎:gateway_timeout
505 ‎:http_version_not_supported
506 ‎:variant_also_negotiates
507 ‎:insufficient_storage
508 ‎:loop_detected
510 ‎:not_extended
511 ‎:network_authentication_required

ملاحظة: إذا حاولت تصيير محتوى مع رمز حالة انعدام المحتوى (non-content status code، أي 100-199 أو 204 أو 205 أو 304) ، فسيُحذَف من الاستجابة.

الخيار :format

يستخدم ريلز التنسيق المحدد في الطلب (أو :html بشكل افتراضي). يمكنك تغيير هذا بتمرير الخيار :formats مع رمز أو مصفوفة:

render formats: :xml
render formats: [:json, :xml]

في حالة عدم وجود قالب بالتنسيق المحدد، فسيرمى الخطأ ActionView::MissingTemplate.

البحث عن التخطيطات

للعثور على التخطيط الحالي، تبحث ريلز أولًا عن ملف في app/views/layouts بنفس الاسم الأساسي للمتحكم. على سبيل المثال، سيؤدي استخدام Action View من الصنف PhotosController إلى استخدام app/views/layouts/photos.html.erb (أو app/views/layouts/photos.builder). إذا لم يكن هناك تخطيط محدد لهذا المتحكم، فستستخدم ريلز app/views/layouts/application.html.erb أو app/views/layouts/application.builder. إذا لم يكن هناك تخطيط ‎.erb، فسوف يستخدم ريلز التخطيط ‎.builder إذا كان موجودًا. توفر ريلز أيضًا عدة طرق لتعيين تخطيطات محددة بدقة أكبر لمتحكمات وأحداث فردية.

تحديد التخطيطات للمتحكمات

يمكنك تخطي العرف المتعلق بالتخطيط الافتراضي في متحكماتك الخاصة عبر استعمال التصريح layout. فمثلا:

class ProductsController < ApplicationController
  layout "inventory"
  #...
end

باستخدام هذا التصريح، ستستخدم جميع العروض المصيَّرة بواسطة ProductsController الملف app/views/layouts/inventory.html.erb كتخطيط لها. لتعيين تخطيط محدد للتطبيق بالكامل، استخدم التصريح layout في الصنف ApplicationController الخاصة بك:

class ApplicationController < ActionController::Base
  layout "main"
  #...
end

باستخدام هذا التصريح، ستَستخدم جميعُ العروض في التطبيق الملف app/views/layouts/main.html.er تخطيطًا لها.

اختيار التخطيطات في وقت التشغيل

يمكنك استخدام رمز لتأجيل اختيار التخطيط حتى تتم معالجة الطلب:

class ProductsController < ApplicationController
  layout :products_layout
 
  def show
    @product = Product.find(params[:id])
  end
 
  private
    def products_layout
      @current_user.special? ? "special" : "products"
    end
 
end

الآن، إذا كان المستخدم الحالي مستخدمًا خاصًا، فسيحصل على تخطيط خاص عند عرض أحد المنتجات. يمكنك حتى استخدام تابع مضمن، مثل Proc، لتحديد التخطيط. على سبيل المثال، إذا قمت بتمرير كائن من النوع Proc، فستُعطَى الكتلة التي تعطيها الكائن Proc النسخة controller، بحيث يمكن تحديد التخطيط بناءً على الطلب الحالي:

class ProductsController < ApplicationController
  layout Proc.new { |controller| controller.request.xhr? ? "popup" : "application" }
end
التخطيطات الشرطية

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

class ProductsController < ApplicationController
  layout "product", except: [:index, :rss]
end

باستخدام هذا التعريف، سيُستخدَم التخطيط product لكل شيء باستثناء التابعين rss و index.

وراثة التخطيط

تتوالى (cascade) تصريحات التخطيط لأسفل في التسلسل الهرمي، وتحل تصريحات التخطيط الأكثر تحديدًا دائمًا مكان التصريحات الأكثر عامية. فمثلًا:

  • الملف application_controller.rb
class ApplicationController < ActionController::Base
  layout "main"
end
  • الملف articles_controller.rb
class ArticlesController < ApplicationController
end
  • الملف special_articles_controller.rb
class SpecialArticlesController < ArticlesController
  layout "special"
end
  • الملف old_articles_controller.rb
class OldArticlesController < SpecialArticlesController
  layout false
 
  def show
    @article = Article.find(params[:id])
  end
 
  def index
    @old_articles = Article.older
    render layout: "old"
  end
  # ...
end

في هذا التطبيق:

  • بشكل عام، ستصيَّر العروض في التخطيط main.
  • سيستخدم ArticlesController.index التخطيط main.
  • سيستخدم SpecialArticlesController.index التخطيط special.
  • لن يستخدم OldArticlesController.show أي تخطيط على الإطلاق.
  • سيستخدم OldArticlesController.index التخطيط old.
وراثة القالب

كما هو الحال مع منطق "وراثة التخطيط"، إذا لم يُعثَر على قالب أو جزء منه في المسار التقليدي، فسيبحث المتحكم عن قالب أو جزء منه ليصيِّره في سلسلة الوراثة الخاصة به. فمثلًا:

# app/controllers/application_controller في
class ApplicationController < ActionController::Base
end
 
# app/controllers/admin_controller في
class AdminController < ApplicationController
end
 
# app/controllers/admin/products_controller في
class Admin::ProductsController < AdminController
  def index
  end
end

سيكون ترتيب البحث للإجراء index/products.index هو:

  • /app/views/admin/products
  • /app/views/admin
  • /app/views/application

وهذا يجعل app/views/application/ مكانًا رائعًا لجزئياتك (partials) المشتركة، والتي يمكن تصييرها في القالب ERB كالتالي:

<%# app/views/admin/products/index.html.erb %>
<%= render @products || "empty_list" %>
 
<%# app/views/application/_empty_list.html.erb %>
There are no items in this list <em>yet</em>.
تجنب أخطاء التصيير المضاعف

عاجلًا أم آجلًا، سيشاهد معظم مطوري ريلز رسالة الخطأ "Can only render or redirect once per action" (أي لا يمكن عرض أو إعادة التوجيه إلا مرة واحدة لكل إجراء). في حين أن هذا أمر مزعج، فإنه من السهل نسبيًا إصلاحه. عادة ما يحدث ذلك بسبب سوء فهم أساسي للطريقة التي تعمل التابع render بها.

على سبيل المثال، إليك بعض الشيفرات التي ستؤدي إلى ظهور هذا الخطأ:

def show
  @book = Book.find(params[:id])
  if @book.special?
    render action: "special_show"
  end
  render action: "regular_show"
end

إذا كان الاستدعاء ‎@book.special?‎ يعيد القيمة true، سيبدأ ريلز عملية التصيير لتفريغ المتغير book@ في العرض special_show. ولكن هذا لن يوقف بقية الشيفرة في الإجراء show من العمل، وعندما تصل ريلز إلى نهاية الإجراء، فإنه سيبدأ في بتصيير العرض regular_show، وإلقاء خطأ. الحل بسيط: تأكد من استدعاء render أو redirect مرةً واحدةً في الوقت ذاته في الشيفرة نفسها. شيء آخر يمكن أن يساعد هو استعمال and return. وإليك نسخة مصححة من المثال السابق:

def show
  @book = Book.find(params[:id])
  if @book.special?
    render action: "special_show" and return
  end
  render action: "regular_show"
end

تأكد من استخدام and return بدلًا من return && لأن الأخيرة لن تعمل نتيجة أسبقية المعامل في لغة روبي. لاحظ أنَّ التصيير الضمني الذي قام به المتحكم ActionController يكتشف إذا استُدعي render، لذلك ستعمل الشيفرة التالية دون أخطاء:

def show
  @book = Book.find(params[:id])
  if @book.special?
    render action: "special_show"
  end
end

هذا سيصيِّر كتابًا (book) مع ضبط special?‎ مع القالب special_show، بينما ستصيَّر الكتب الأخرى باستخدام القالب show الافتراضي.

استخدام redirect_to

هناك طريقة أخرى لمعالجة الاستجابات العائدة من طلبية HTTP وهي redirect_to. كما شاهدت، يخبر التابع render ريلز أي عرض (أو أصل آخر) سيُستخدَم في إنشاء استجابة. يفعل التابع redirect_to شيئًا مختلفًا تمامًا؛ فهو يخبر المتصفح بإرسال طلبية جديدة لعنوان URL مختلف. على سبيل المثال، يمكنك إعادة التوجيه من أي مكان توجد فيه في شيفرتك إلى فهرس الصور في تطبيقك باستخدام هذا الاستدعاء:

redirect_to photos_url

يمكنك استخدام redirect_back لإعادة المستخدم إلى الصفحة التي جاء منها للتو. يُسحَب هذا الموقع من الترويسة HTTP_REFERER التي لا يُضمَن أن يضبطها المتصفح، لذلك يجب تمرير fallback_location لاستخدامه في هذه الحالة.

redirect_back(fallback_location: root_path)

ملاحظة: لا يتوقف كل من redirect_to و redirect_back ويعودان فورًا من تنفيذ التابع، ولكن ببساطة يعينان استجابات HTTP. ستنفَّذ التعليمات البرمجية التي بعدهما في تابعٍ. يمكنك إيقاف التنفيذ عن طريق استعمال return بصراحة أو باستعمال آلية إيقاف أخرى، إذا لزم الأمر.

الحصول على رمز حالة مختلف لإعادة التوجيه

يستخدم ريلز رمز الحالة HTTP 302 الذي يشير إلى إعادة توجيه مؤقتة (temporary redirect)، عندما تستدعي redirect_to. إذا كنت ترغب في استخدام رمز حالة مختلف، ربما 301، أو إعادة توجيه دائمة، فيمكنك استخدام الخيار :status:

redirect_to photos_path, status: 301

تمامًا مثل الخيار :status للتابع render، يقبل الخيار :status في التابع redirect_to تسميات الترويسة الرقمية أو الرمزية.

الفرق بين render و redirect_to

يعتقد المطورون عديمو الخبرة أحيانًا أنَّ التابع redirect_to هو شيء شبيه بالأمر goto، الذي ينقل التنفيذ من مكان إلى آخر في شيفرة ريلز وهذا خطأ بالتأكيد. تتوقف آنذاك شيفرتك عن العمل وتنتظر طلبًا جديدًا للمتصفح؛ ما يحدث هو فقط أنك أخبرت المتصفح بالطلب الذي يجب أن تقدمه بعد ذلك، عن طريق إرسال رمز الحالة HTTP 302.

فكر في الإجراءين التاليين لمعرفة الفرق:

def index
  @books = Book.all
end
 
def show
  @book = Book.find_by(id: params[:id])
  if @book.nil?
    render action: "index"
  end
end

مع الشيفرة في هذا النموذج، من المحتمل أن يكون هناك مشكلة إذا كان المتغير book@ فارغًا. تذكر أن render :action لا يُشغِّل أي شيفرة في الإجراء المستهدف، لذلك لن يقوم أي شيء بإعداد المتغير books@ الذي قد يتطلبه العرض index على الأرجح. إحدى طرق حل هذه المشكلة هي إعادة التوجيه بدلاً من التصيير:

def index
  @books = Book.all
end
 
def show
  @book = Book.find_by(id: params[:id])
  if @book.nil?
    redirect_to action: :index
  end
end

باستخدام هذه الشيفرة، سيقدم المتصفح طلبًا جديدًا للصفحة index، وستُشغَّل الشيفرة في التابع index، وسيكون كل شيء على ما يرام.

الجانب السلبي الوحيد لهذه الشيفرة هو أنه يتطلب رحلة ذهابًا وإيابًا إلى المتصفح: طَلَبَ المتصفح الإجراء show مع ‎/books/1، فوجد المتحكم أنه لا توجد كتب، لذلك يرسل المتحكم استجابة لإعادة التوجيه بالرمز ‎302 إلى المتصفح لإخباره بالذهاب إلى /books/؛ يمتثل المتصفح ويرسل طلبًا جديدًا مرةً أخرى إلى المتحكم يطلب فيه الإجراء index، ثم يحصل المتحكم على جميع الكتب من قاعدة البيانات ويصيِّر القالب index، ويعيد إرساله إلى المتصفح الذي يعرضه على شاشتك.

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

def index
  @books = Book.all
end
 
def show
  @book = Book.find_by(id: params[:id])
  if @book.nil?
    @books = Book.all
    flash.now[:alert] = "Your book was not found"
    render "index"
  end
end

سيكشف هذا عن عدم وجود كتب مع المعرّف المحدد، وينشر (populate) متغير النسخة ‎@books بكافة الكتب في النموذج، ثم يصيِّر القالب index.html.erb مباشرة ويعيده إلى المتصفح برسالة تنبيه (flash alert message) تخبر المستخدم بما قد حدث.

استخدام head لإنشاء استجابات من الترويسات فقط

يمكن استخدام التابع head لإرسال ردود مع ترويسات فقط للمتصفح. يقبل التابع head عددًا أو رمزًا (اطلع على الجدول المرجعي الموجود في قسم الخيار :status) الذي يمثل رمز حالة HTTP. يفسَر وسيط الخيارات (options argument) على أنه جدول Hash يحوي أسماء وقيم الترويسة. على سبيل المثال، يمكنك إعادة ترويسة خطأٍ فقط عبر:

head :bad_request

سُينتج هذا الترويسة التالية:

HTTP/1.1 400 Bad Request
Connection: close
Date: Sun, 24 Jan 2010 12:15:53 GMT
Transfer-Encoding: chunked
Content-Type: text/html; charset=utf-8
X-Runtime: 0.013483
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache

أو يمكنك استخدام ترويسات HTTP أخرى لنقل معلومات أخرى عبر:

head :created, location: photo_path(@photo)

التي ستنتج:

HTTP/1.1 201 Created
Connection: close
Date: Sun, 24 Jan 2010 12:16:44 GMT
Transfer-Encoding: chunked
Location: /photos/1
Content-Type: text/html; charset=utf-8
X-Runtime: 0.083496
Set-Cookie: _blog_session=...snip...; path=/; HttpOnly
Cache-Control: no-cache

هيكلة التخطيطات

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

  • وسوم الأصول
  • yield و content_for
  • الجزئيات

مساعدو وسم الأصول

يوفر مساعدو وسم الأصول (Asset tag helpers) توابعًا لتوليد شيفرة HTML تربط عروضًا بتغذية (feed)، وشيفرة جافاسكربت، وأوراق الأنماط، والصور، ومقاطع الفيديو، وتسجيلات الصوت. يوجد ستة مساعدين لوسوم الأصول في ريلز هي:

  • auto_discovery_link_tag
  • javascript_include_tag
  • stylesheet_link_tag
  • image_tag
  • video_tag
  • audio_tag

يمكنك استخدام هذه الوسوم في التخطيطات أو عروض أخرى، على الرغم من أنَّ auto_discovery_link_tag و javascript_include_tag و stylesheet_link_tag تستخدم بشكل شائع ضمن <head> في أي تخطيط.

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

ربط التغذيات مع المساعد auto_discovery_link_tag

ينشئ المساعد auto_discovery_link_tag شيفرة HTML يمكن لمعظم المتصفحات وقارئات التغذية استخدامها للكشف عن وجود تغذية RSS أو Atom أو JSON. يأخذ المساعد نوع الرابط (‎:rss، أو ‎:atom، أو ‎:json)، وجدول Hash من الخيارات التي تُمَرَّر إلى url_for، وجدول Hash من الخيارات للوسم:

<%= auto_discovery_link_tag(:rss, {action: "feed"},
  {title: "RSS Feed"}) %>

هناك ثلاثة خيارات متاحة للوسم يمكن استعمالها مع المساعد auto_discovery_link_tag هي:

  • :rel تحدد القيمة rel في الرابط. القيمة الافتراضية هي "alternate".
  • :type يحدد النوع MIME الواضح. سينشئ ريلز نوع MIME مناسبًا تلقائيًا.
  • :title يحدد عنوان الرابط. القيمة الافتراضية هي الأحرف الكبيرة للقيمة :type مثل "ATOM" أو "RSS".

ربط ملفات جافاسكربت مع javascript_include_tag

يعيد المساعد javascript_include_tag الوسم <script> الخاص بلغة HTML لكل مصدر معطى.

إذا كنت تستخدم ريلز مع تمكين خط أنابيب الأصول، سينشئ هذا المساعد رابطًا إلى /assets/javascripts/ بدلاً من public/javascripts الذي كان مستخدَمًا في الإصدارات السابقة من ريلز. ثم هذا الرابط يُخدَم بواسطة خطا أنابيب الأصول (asset pipeline).

يوضع ملف جافاسكربت داخل أحد تطبيقات ريلز أو محرك ريلز في أحد المواقع الثلاثة:

  • app/assets، أو
  • lib/assets، أو
  • vendor/assets.

شُرحَت هذه المواقع بالتفصيل في قسم تنظيم الأصول في دليل خط أنابيب الأصول.

تستطيع تحديد مسار كامل يتعلق بجذر المستند، أو عنوان URL، إذا أردت ذلك. على سبيل المثال، للارتباط بملف JavaScript موجود داخل مجلد يسمى javascripts داخل app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:

<%= javascript_include_tag "main" %>

بعد ذلك، سيولد ريلز الوسم <script> التالي:

<script src='/assets/main.js'></script>

ثم يُقدَّم الطلب إلى هذا الأصل بواسطة الجوهرة Sprockets. لتضمين ملفات متعددة مثل app/assets/javascripts/main.js و app/assets/javascripts/columns.js في الوقت نفسه، جرب ما يلي:

<%= javascript_include_tag "main", "columns" %>

لتضمين app/assets/javascripts/main.js و app/assets/javascripts/photos/columns.js:

<%= javascript_include_tag "main", "/photos/columns" %>

لتضمين http://example.com/main.js:

<%= javascript_include_tag "http://example.com/main.js" %>

ربط ملفات CSS باستخدام stylesheet_link_tag

يُعيد المساعد stylesheet_link_tag الوسم <link> لكل مصدر معطى.

إذا كنت تستخدم ريلز مع تمكين خط أنابيب الأصول، فسينشئ هذا المساعد رابطًا إلى /assets/stylesheets/ ثم يُعالَج هذا الرابط بعد ذلك بواسطة الجوهرة Sprockets. يمكن تخزين ملف ورقة الأنماط في أحد المواقع الثلاثة:

  • app/assets، أو
  • lib/assets، أو
  • vendor/assets.

تستطيع تحديد مسار كامل نسبةً إلى جذر المستند، أو عنوان URL، على سبيل المثال، للارتباط بملف ورقة أنماط موجود داخل مجلد يسمى stylesheets داخل المجلد app/assets، أو lib/assets، أو vendor/assets، يمكنك القيام بذلك:

<%= stylesheet_link_tag "main" %>

لتضمين app/assets/stylesheets/main.css و app/assets/stylesheets/columns.css:

<%= stylesheet_link_tag "main", "columns" %>

لتضمين app/assets/stylesheets/main.css و app/assets/stylesheets/photos/columns.css:

<%= stylesheet_link_tag "main", "photos/columns" %>

لتضمين http://example.com/main.css:

<%= stylesheet_link_tag "http://example.com/main.css" %>

بشكل افتراضي، يُنشئ stylesheet_link_tag روابط مع media="screen" rel="stylesheet"‎. يمكنك تجاوز أيَّا من هذه القيم الافتراضية عن طريق تحديد الخيار المناسب (:media، أو ):

<%= stylesheet_link_tag "main_print", media: "print" %>

ربط الصور باستخدام image_tag

ينشئ المساعد image_tag الوسم <img /‎> إلى الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من public/images.

تحذير: لاحظ أنه يجب عليك تحديد امتداد الصورة.

<%= image_tag "header.png" %>

يمكنك توفير مسار للصورة إذا أردت:

<%= image_tag "icons/delete.gif" %>

يمكنك توفير جدول Hash من خيارات HTML الإضافية:

<%= image_tag "icons/delete.gif", {height: 45} %>

يمكنك توفير نص بديل للصورة يُستخدَم إذا أوقف المستخدِم تشغيل الصور في المتصفح. إذا لم تُحدد نص بديل بشكل صريح، فسيُعيَّن افتراضيًا باسم الملف بأحرف كبيرة وبدون اللاحقة. على سبيل المثال، قد تعيد هاتان الصورتان نفس الشيفرة:

<%= image_tag "home.gif" %>
<%= image_tag "home.gif", alt: "Home" %>

يمكنك أيضًا تحديد حجم خاص للصورة عبر التنسيق "{width} x {height}":

<%= image_tag "home.gif", size: "50x20" %>

بالإضافة إلى الخيارات الخاصة المذكورة أعلاه، يمكنك توفير جدول Hash في النهاية لخيارات HTML القياسية، مثل :class، أو :id، أو :name:

<%= image_tag "home.gif", alt: "Go Home",
                          id: "HomeImage",
                          class: "nav_bar" %>

ربط مقاطع الفيديو مع video_tag

ينشئ المساعد video_tag الوسم <video> الذي وفرته HTML5 لتضمين مقاطع الفيديو. بشكل افتراضي، تُحمَّل الملفات الفيديو من المجلد public/videos.

<%= video_tag "movie.ogg" %>

يُنتِج:

<video src="/videos/movie.ogg" />

مثل image_tag، يمكنك توفير مسار، إما مطلق، أو نسبي إلى المجلد public/videos. بالإضافة إلى ذلك، يمكنك تحديد الحجم عبر التنسيق "‎#{width}x#{height‎}‎" تمامًا مثل image_tag. يمكن أن تحتوي وسوم الفيديو أيضًا على أي من خيارات HTML المحددة في النهاية (مثل الخيار :class، أو :id، أو :name).

يدعم وسم الفيديو أيضًا جميع خيارات <video> من خلال وضع خيارات HTML هذه ضمن جدول Hash من ضمنها:

  • poster: "image_name.png"‎، يوفر صورة لعرضها في واجهة الفيديو قبل بدء تشغيله.
  • autoplay: true، يبدأ تشغيل الفيديو عند تحميل الصفحة.
  • loop: true، يكرر الفيديو بمجرد انتهاء تشغليه.
  • controls: true، يوفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الفيديو.
  • autobuffer: true، سيحمِّل الفيديو الملف مسبقًا للمستخدم أثناء تحميل الصفحة.

يمكنك أيضًا تحديد عدة مقاطع فيديو لتشغيلها بتمرير مصفوفة من مقاطع الفيديو إلى video_tag:

<%= video_tag ["trailer.ogg", "movie.ogg"] %>

هذا سينتج:

<video>
  <source src="/videos/trailer.ogg">
  <source src="/videos/movie.ogg">
</video>

ربط الملفات الصوتية مع audio_tag

ينشئ المساعد audio_tag الوسم <audio>  على الملف المحدد. بشكل افتراضي، تُحمَّل الملفات من المجلد public/audios.

<%= audio_tag "music.mp3" %>

يمكنك توفير مسار للملف الصوتي إذا كنت ترغب بذلك بالشكل:

<%= audio_tag "music/first_song.mp3" %>

يمكنك أيضًا توفير مجموعة متنوعة من الخيارات، مثل :class و :id ...إلخ.

مثل المساعد video_tag، يحتوي audio_tag على خيارات خاصة هي:

  • autoplay: true، يبدأ تشغيل الصوت عند تحميل الصفحة.
  • controls: true، يوفر عناصر التحكم التي يوفرها المتصفح للمستخدم للتفاعل مع الصوت.
  • autobuffer: true، سيحمل ملف الصوت الملف للمستخدم أثناء تحميل الصفحة.

فهم yield

في سياق أي تخطيط، يعرِّف yield قسمًا حيث يجب إدراج المحتوى من العرض. تتمثل أبسط طريقة لاستخدام هذا في الحصول على yield واحدٍ يُدرَج فيه محتويات العرض قيد التصيير حاليًا:

<html>
  <head>
  </head>
  <body>
  <%= yield %>
  </body>
</html>

يمكنك أيضًا استعمال yield أكثر من مرة ضمن التخطيط:

<html>
  <head>
  <%= yield :head %>
  </head>
  <body>
  <%= yield %>
  </body>
</html>

سيصيَّر دائمًا الجسم الرئيسي في yield غير المسمى. لتصيير محتوى إلى yield محدد، تستطيع استخدم التابع content_for.

استخدام التابع content_for

يسمح لك التابع content_for بإدراج محتوى في كتلة yield محددة في تخطيطك. على سبيل المثال، قد يعمل هذا العرض مع التخطيط التي شاهدته للتو:

<% content_for :head do %>
  <title>A simple page</title>
<% end %>
 
<p>Hello, Rails!</p>

ستكون نتيجة تصيير هذه الصفحة في التخطيط المعطى هي شيفرة HTML التالية:

<html>
  <head>
  <title>A simple page</title>
  </head>
  <body>
  <p>Hello, Rails!</p>
  </body>
</html>

التابع content_for مفيد للغاية عندما يحتوي تخطيطك على مناطق مميزة مثل الأقسام الجانبية (sidebars) والتذييلات التي يجب أن تُدرَج كتلها الخاصة بها. كما يفيد أيضًا في إدراج الوسوم التي تحمّل ملفات جافاسكربت أو ملفات CSS الخاصة بالصفحة في رأس تخطيط آخر عام.

استخدام الجزئيات

القوالب الجزئية - عادة ما تسمى "الجزئيات" (partials) - هي أداة أخرى لتجزئة عملية التصيير إلى أجزاء أكثر قابلية للإدارة. باستخدام جزئية، يمكنك نقل الشيفرة لتصيير جزء معين من الاستجابة لملفها الخاص.

تسمية الجزئيات

لتصيير جزئية كجزء من عرض، فاستخدم التابع render في العرض:

<%= render "menu" %>

سيؤدي ذلك إلى تصيير ملف يدعى ‎_menu.html.erb في تلك النقطة داخل العرض قيد التصيير. لاحظ الشرطة السفلية البادئة لاسم الملف: تبدأ أسماء الجزئيات بشرطة سفلية لتمييزها عن العروض العادية، رغم أنه يشار إليها بدون الشرطة السفلية. هذا صحيح حتى عند سحب جزء من مجلد آخر:

<%= render "shared/menu" %>

ستسحب (pull) هذه الشيفرة في الجزئية من app/views/shared/_menu.html.erb.

استخدام الجزئيات لتبسيط العروض

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

<%= render "shared/ad_banner" %>
<h1>Products</h1>
<p>Here are a few of our fine products:</p>
...
<%= render "shared/footer" %>

هنا، يمكن أن تحتوي كل من الجزئية ‎_ad_banner.html.erb و ‎_footer.html.erb على محتوى مشترك من قبل العديد من الصفحات في تطبيقك. لست بحاجة إلى الاطلاع على تفاصيل هذه الأقسام عند التركيز على صفحة معينة.

كما هو موضح في الأقسام السابقة من هذا الدليل، تعدُّ yield أداةً قويةً جدًا لتنظيف تخطيطاتك. ضع في اعتبارك أنها شيفرة روبي صرفة، لذلك يمكنك استخدامها في كل مكان تقريبا. على سبيل المثال، يمكننا استخدام الجزئيات لتقليل تعريفات تخطيط نموذج لعدة مصادر متشابهة:

  • الملف users/index.html.erb
<%= render "shared/search_filters", search: @q do |f| %>
  <p>
    Name contains: <%= f.text_field :name_contains %>
  </p>
<% end %>
  • الملف roles/index.html.erb
<%= render "shared/search_filters", search: @q do |f| %>
  <p>
    Title contains: <%= f.text_field :title_contains %>
  </p>
<% end %>
  • الملف shared/_search_filters.html.erb
<%= form_for(search) do |f| %>
  <h1>Search form:</h1>
  <fieldset>
    <%= yield f %>
  </fieldset>
  <p>
    <%= f.submit "Search" %>
  </p>
<% end %>

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

التخطيطات الجزئية

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

<%= render partial: "link_area", layout: "graybar" %>

سيبحث هذا عن جزئية اسمها ‎_link_area.html.erb ويصيِّرها باستخدام التخطيط ‎_graybar.html.erb. لاحظ أن التخطيط الخاص بالجزئيات يتبع نفس نمط تسمية الجزئيات نفسها (البدء بشرطة سفلية)، ويوضع في نفس المجلد مع الجزئية التي ينتمي إليها (وليس في مجلد التخطيطات الرئيسي).

لاحظ أيضًا التحديد :‎partial الصريح هذا مطلوب عند تمرير خيارات إضافية مثل الخيار :layout.

تمرير متغيرات محلية

يمكنك أيضًا تمرير متغيرات محلية إلى الجزئيات، مما يجعلها أكثر قوة ومرونة. على سبيل المثال، يمكنك استخدام هذه التقنية لتقليل التكرار بين الصفحات الجديدة والمعدلَّة، مع الاحتفاظ بقليل من المحتوى المميز:

  • الملف new.html.erb
<h1>New zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>
  • الملف edit.html.erb
<h1>Editing zone</h1>
<%= render partial: "form", locals: {zone: @zone} %>
  • الملف form.html.erb_
<%= form_for(zone) do |f| %>
  <p>
    <b>Zone name</b><br>
    <%= f.text_field :name %>
  </p>
  <p>
    <%= f.submit %>
  </p>
<% end %>

رغم أن الجزئية نفسها ستصيِّر في كلا العرضين، فسيعيد مساعد إرسال Action View القيمة "Create Zone" للإجراء new والقيمة "Update Zone" للإجراء edit.

لتمرير متغير محلي إلى جزئية في حالات محددة فقط، استخدم local_assigns.

  • الملف index.html.erb
<%= render user.articles %>
  • الملف show.html.erb
<%= render article, full: true %>
  • الملف article.html.erb_
<h2><%= article.title %></h2>
 
<% if local_assigns[:full] %>
  <%= simple_format article.body %>
<% else %>
  <%= truncate article.body %>
<% end %>

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

<%= render partial: "customer", object: @new_customer %>

داخل الجزئية customer، سيشير المتغير customer إلى ‎@new_customer من العرض الرئيسي. إذا كان لديك نسخةً لنموذج لتصييره إلى جزئية، فيمكنك استخدام صيغة مختصرة بالشكل التالي:

<%= render @customer %>

بافتراض أن متغير النسخة ‎@customer يحتوي على نسخة للنموذج Customer، سيستخدم هذا ‎_customer.html.erb لتصييره ثم سيمرر المتغير المحلي customer إلى الجزئية التي ستشير إلى متغير النسخة ‎@customer في العرض الأصلي.

تصيير المجموعات

الجزئيات مفيدة للغاية في تصيير المجموعات. عند تمريرك مجموعة إلى جزئية عبر الخيار :collection، ستُدرَج الجزئية مرة واحدة لكل عضو في المجموعة:

  • الملف index.html.erb
<h1>Products</h1>
<%= render partial: "product", collection: @products %>
  • الملف product.html.erb_
<p>Product Name: <%= product.name %></p>

عندما تُستدعى جزئية ما مع مجموعة متعددة، فإن النسخ الفردية للجزئية يكون لها حق الوصول إلى عضو المجموعة الذي يجري تصييره عبر متغير مسمى بعد الجزئية. في هذه الحالة، الجزئية هي product_، وضمن الجزئية product_، يمكنك الإشارة إلى product للحصول على النسخة التي يجري تصييرها. هناك أيضا اختزال لهذه العملية. بافتراض أن ‎@products عبارة عن مجموعة من نسخ من product، يمكنك ببساطة كتابة هذا في الملف index.html.erb للحصول على النتيجة نفسها:

<h1>Products</h1>
<%= render @products %>

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

  • الملف index.html.erb
<h1>Contacts</h1>
<%= render [customer1, employee1, customer2, employee2] %>
  • الملف customers/_customer.html.erb
<p>Customer: <%= customer.name %></p>
  • الملف employees/_employee.html.erb
<p>Employee: <%= employee.name %></p>

في هذه الحالة، سيستخدم ريلز الجزئية customer أو الجزئية employee بما بناسب كل عضو في المجموعة. إذا كانت المجموعة فارغة، سيعيد التابع render القيمة nil، لذلك يجب أن يكون من السهل توفير محتوى بديل.

<h1>Products</h1>
<%= render(@products) || "There are no products available." %>

المتغيرات المحلية

لاستخدام اسم متغير محلي مخصص داخل الجزئية، حدد الخيار :as أثناء استدعاء الجزئية:

<%= render partial: "product", collection: @products, as: :item %>

باستخدام هذا التغيير، يمكنك الوصول إلى نسخة للمجموعة ‎@products باعتباره المتغير المحلي item داخل الجزئية. يمكنك أيضًا تمرير متغيرات محلية عشوائية إلى أي جزئية تصييرها مع الخيار المحليين locals: {}‎:

<%= render partial: "product", collection: @products,
           as: :item, locals: {title: "Products Page"} %>

في هذه الحالة، ستحصل الجزئية على حق الوصول إلى المتغير المحلي title ذي القيمة "Products Page".

تنويه: يجعل ريلز أيضًا متغير عداد (counter variable) متاحًا داخل جزئية تستدعى بواسطة المجموعة، يسمى بعد عنوان الجزئية متبوعًا بالعبارة counter_. على سبيل المثال، عند عرض مجموعة باسم products@، يمكن للجزئية product.html.erb_ الوصول إلى المتغير product_counter الذي يفهرس عدد العناصر التي صُيِّرَت داخل العرض المرفق.

يمكنك أيضًا تحديد جزئية ثانية لتصييرها بين نسخ الجزئية الرئيسية باستخدام الخيار :spacer_template.

قوالب الفصل

<%= render partial: @products, spacer_template: "product_ruler" %>

ستصيِّر ريلز الجزئية product_ruler_ (دون تمرير بيانات إليها) بين كل زوج من الجزئيات product_.

مجموعة التخطيطات الجزئية

عند تصيير المجموعات، يمكن أيضًا استخدام الخيار :layout:

<%= render partial: "product", collection: @products, layout: "special_layout" %>

سيُصيَّر التخطيط مع الجزئية لكل عنصر في المجموعة. سيتوفر المتغيران object و object_counter الحاليان في التخطيط أيضًا، تمامًا كما هما داخل الجزئية.

استخدام التخطيطات المتداخلة

قد تجد أن تطبيقك يتطلب تخطيطًا يختلف قليلًا عن تخطيط تطبيقك العادي لدعم متحكم معين. بدلًا من تكرار التخطيط الرئيسي وتعديله، يمكنك القيام بذلك باستخدام التخطيطات المتداخلة (nested layouts، تسمى أحيانًا القوالب الفرعية [sub-templates]). هنا مثال:

لنفترض أن لديك التخطيط ApplicationController التالي:

  • الملف app/views/layouts/application.html.erb
<html>
<head>
  <title><%= @page_title or "Page Title" %></title>
  <%= stylesheet_link_tag "layout" %>
  <style><%= yield :stylesheets %></style>
</head>
<body>
  <div id="top_menu">Top menu items here</div>
  <div id="menu">Menu items here</div>
  <div id="content"><%= content_for?(:content) ? yield(:content) : yield %></div>
</body>
</html>

في الصفحات المولدة بواسطة NewsController، تريد إخفاء القائمة العلوية وإضافة قائمة يمينية:

  • الملف app/views/layouts/news.html.erb
<% content_for :stylesheets do %>
  #top_menu {display: none}
  #right_menu {float: right; background-color: yellow; color: black}
<% end %>
<% content_for :content do %>
  <div id="right_menu">Right menu items here</div>
  <%= content_for?(:news_content) ? yield(:news_content) : yield %>
<% end %>
<%= render template: "layouts/application" %>

انتهينا! ستَستخدم العروض News التخطيط الجديد، الذي يخفي القائمة العلوية ويضيف قائمة يمينية جديدة في العنصر <div> ذي المعرف content.

هناك عدة طرق للحصول على نتائج مشابهة مع أنظمة التخطيط الفرعية المختلفة باستخدام هذه التقنية. لاحظ أنه لا يوجد حد في مستويات التداخل. يمكن استخدام التابع ActionView::render عبر render template: 'layouts/news'‎ لتأسيس تخطيط جديدة في التخطيط News. إذا كنت متأكدًا من أنك لن تفرِّع (subtemplate) قالبًا من التخطيط News، فيمكنك تبديل yield مكان content_for?(:news_content) ? yield(:news_content) : yield ببساطة.

مصادر