الشروع في العمل مع المحركات في ريلز

من موسوعة حسوب
اذهب إلى التنقل اذهب إلى البحث

ستتعرف في هذا الدليل على المحركات (engines) وكيف يمكن استخدامها لتوفير وظائف إضافية لتطبيقاتها المضيفة من خلال واجهة واضحة وسهلة الاستخدام للغاية.

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

  • مما يتكون المحرك.
  • كيف وُلِّد المحرك.
  • كيفية بناء ميزات للمحرك.
  • كيفية ربط المحرك في التطبيق.
  • كيفية استبدال وظيفة المحرك في التطبيق.
  • تجنب تحميل أطر ريلز مع خطافات التحميل (Load Hooks) وخطافات الضبط (Configuration Hooks).

ما هي المحركات؟

تُعدُّ المحركات تطبيقات مصغرة توفر وظائف لتطبيقاتها المضيفة. تطبيق ريلز هو بالفعل محرك "supercharged"، مع الصنف Rails::Application الذي يرث الكثير من سلوكه من Rails::Engine.

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

ترتبط المحركات أيضًا ارتباطًا وثيقًا بالمكونات الإضافية. يشترك الاثنان في بنية المجلد lib، وكلاهما يُنشَأ باستخدام المولِّد rails plugin new. الفرق هو أن المحرك يعتبر "إضافة كاملة" (full plugin) بواسطة ريلز (كما هو مشار إليه في الخيار ‎--full الذي يُمررإلى أمر المولد).

سنستخدم في الواقع الخيار ‎--mountable هنا، والذي يتضمن جميع ميزات ‎--full. سيشير هذا الدليل إلى هذه "الإضافات الكاملة" ببساطة على أنَّها "المحركات" طوال الوقت. يمكن أن يكون المحرك إضافةً ويمكن أن تكون الإضافة محركًا.

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

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

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

لمشاهدة عروض محركات أخرى، تحقق من Devise، وهو محرك يوفر الاستيثاق لتطبيقاته الرئيسية، أو Thredded، وهو محرك يوفر وظائف منتدى (forum). هناك أيضا Spree الذي يوفر منصة تجارة إلكترونية، و Refinery CMS، الذي يعد محرك نظام إدارة محتوى (CMS).

وأخيرًا، لم تكن المحركات ممكنة بدون أعمال James Adam و Piotr Sarnacki وفريق ريلز الأساسي وعدد آخر من الأشخاص. إذا قابلتهم في أي وقت، لا تنسَ أن تقول لهم شكرًا!

توليد محرك

لتوليد محركٍ، سوف تحتاج لتشغيل المولد plugin وتمرير الخيارات بما يتناسب مع الحاجة. لتوليد المثال "blorgh"، ستحتاج إلى إنشاء محرك "قابل للوصل" (mountable)، وتشغيل هذا الأمر في طرفية:

$ rails plugin new blorgh --mountable

يمكن الاطلاع على القائمة الكاملة لخيارات المولد plugin عن طريق الأمر التالي:

$ rails plugin --help

يخبر الخيار mountable-- المولد بأتك تريد إنشاء محرك "قابل للوصل" (mountable) وذي مجال اسم معزول (namespace-isolated). هذا المولد سيوفر نفس الهيكلية كما هو الحال مع الخيار ‎--full. يخبر الخيار ‎--full المولد بأنك تريد إنشاء محركٍ يتضمن البنية الهيكلية التالية:

  • شجرة المجلد app.
  • الملف config/routes.rb:
‎‎Rails.application.routes.draw do
end
  • ملفٌ في lib/blorgh/engine.rb، وهو يماثل وظيفة الملف config/application.rb في تطبيق ريلز القياسي:
module Blorgh
  class Engine < ::Rails::Engine
  end
end

سيضيف الخيار ‎--mountable إلى الخيار ‎--full ما يلي:

  • ملفات بيان الأصول (application.js و application.css).
  • أصل ذو مجال الاسم ApplicationController.
  • أصل ذو مجال الاسم ApplicationHelper.
  • مخطط قالب العرض للمحرك.
  • مجال اسم معزول إلى config/routes.rb:
Blorgh::Engine.routes.draw do
End
  • مجال اسم معزول إلى lib/blorgh/engine.rb:
module Blorgh
  class Engine < ::Rails::Engine
    isolate_namespace Blorgh
  end
end

بالإضافة إلى ذلك، يخبر الخيار ‎--mountable المولد أن يوصل المحرك داخل تطبيق الاختبار الوهمي الموجود في test/dummy بإضافة ما يلي إلى ملف مسارات التطبيق الوهمي في test/dummy/config/routes.rb:

mount Blorgh::Engine => "/blorgh"

داخل المحرك

الملفات الحرجة

في المجلد الجذر، يولد الملف blorgh.gemspec ضمن المجلد engines الجديد. عندما تضمِّن المحرك في التطبيق لاحقًا، ستستخدم السطر التالي في الملف Gemfile الخاص بتطبيق ريلز:

gem 'blorgh', path: 'engines/blorgh'

لا تنسَ تشغيل الأمر bundle install كالمعتاد. من خلال تحديده كجوهرة داخل Gemfile، سيحمله المُحزِّم (Bundler) على هذا النحو، مع تحليل الملف blorgh.gemspec هذا وطلب ملف يدعى lib/blorgh.rb داخل المجلد lib. هذا الملف يتطلب الملف blorgh/engine.rb (الموجود في lib/blorgh/engine.rb) ويُعرِّف وحدة أساسية تسمى Blorgh.

require "blorgh/engine"
 
module Blorgh
end

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

يقبع ضمن lib/blorgh/engine.rb الصنف الأساسي للمحرك:

module Blorgh
  class Engine < ::Rails::Engine
    isolate_namespace Blorgh
  end
end

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

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

بدون هذا، هناك احتمال أن مكونات المحرك يمكن أن "تسرب" في التطبيق، مما تسبب في اضطراب غير مرغوب فيه، أو أن مكونات المحرك المهمة يمكن استبدالها من قبل أشياء مسماة بالاسم نفسه داخل التطبيق. أحد الأمثلة على مثل هذه التضاربات هو المساعدون. دون استدعاء isolate_namespace، سيُضمَّن مساعدو المحرك في وحدات تحكم التطبيق.

ملاحظة: يوصى بشدة أن يترك سطر isolate_namespace داخل تعريف الصنف Engine. بدونه، قد تتضارب الأصناف التي أُنشئت في المحرك مع أحد التطبيقات.

ماذا تعني هذه العزلة في مجال الاسم هي أنَّ النموذج الذي أُنشِئ بواسطة استدعاء bin/rails g model، مثل bin/rails g model article، لن يُسمى Article، ولكن سيكون بدلًا من ذلك مجال اسم يدعى Blorgh::Article. بالإضافة إلى ذلك، يُوضع جدول للنموذج في مجال اسم بدلًا من ذلك، ليصبح blorgh_articles، بدلًا من مجرد articles. وبشكل مماثل لنموذج مجال الأسماء، وحدة تحكم التي تسمى ArticlesController تُصبح Blorgh::ArticlesController، والواجهات لوحدة التحكم لن تكون app/views/articles ولكن ستكون بدلًا من ذلك app/views/blorgh/articles. مرسلي البريد (Mailers) توضع ضمن مجال اسمٍ أيضًا بالأسلوب نفسه أيضًا.

وأخيرًا، ستُعزَل المسارات الموجه داخل المحرك. هذا هو أحد الأجزاء الأكثر أهمية حول تطبيق مجال الأسماء، وسنناقشه لاحقًا في قسم التوجيه في هذا الدليل.

المجلد app

يوجد داخل المجلد app المجلدات assets و controllers و helpers و mailers و models و views القياسية التي يجب أن تكون على دراية بها من أحد التطبيقات. تكون المجلدات helpers و mailers و models فارغةً، لذا لن تُشرَح في هذا القسم. سننظر أكثر في النماذج (models) في قسم لاحق، عندما نكتب المحرك.

ضمن المجلد app/assets، توجد المجلدات images و javascripts و stylesheets التي يجب أن تكون، مرة أخرى، على دراية بها بسبب تشابهها مع أي تطبيق. لكن أحد الاختلافات هنا هو أن كل مجلد يحتوي على مجلد فرعي باسم المحرك. نظرًا لأن هذا المحرك سيوضع ضمن مجال اسم، يجب أن توضع أصوله أيضًا.

يوجد ضمن المجلد app/controllers المجلد blorgh الذي يحتوي على ملف يسمى application_controller.rb. سيوفر هذا الملف أي وظائف مشتركة لوحدات التحكم في المحرك. المجلد blorgh هو المكان الذي سوف تذهب إليه وحدات التحكم الأخرى للمحرك. بوضعها ضمن هذا المجلد الذي يملك مجال اسم، فإنك تمنعهم من التضارب مع وحدات التحكم المسماة باسم مماثل داخل محركات أخرى أو حتى داخل التطبيق.

ملاحظة: تُسمى صنف ApplicationController داخل المحرك مثل تطبيق Rails لتسهيل عملية تحويل التطبيقات إلى محركات.

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

# app/controllers/blorgh/articles_controller.rb:

require_dependency "blorgh/application_controller"

module Blorgh

 class ArticlesController < ApplicationController

   ...

 end

End

لا تتطلب الاستخدام لأنها ستفشل إعادة التحميل التلقائي للفئات في بيئة التطوير - باستخدام require_dependency يضمن أن تُحمل الفئات وتفرغ بالطريقة الصحيحة.

وأخيرا، يحتوي دليل app/views على مجلد تخطيطات، والذي يحتوي على ملف في blorgh / application.html.erb. يتيح لك هذا الملف تحديد تخطيط للمحرك. إذا كان سيستخدم هذا المحرك كمحرك مستقل، فستضيف أي تخصيص لتخطيطه في هذا الملف  بدلاً من ملف التطبيق app/views/layouts/application.html.erb.

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

دليل bin

يحتوي هذا الدليل على ملف واحد، bin / rails، والذي يمكّنك من استخدام الأوامر الفرعية ومولدات rails مثلما تفعل داخل التطبيق. هذا يعني أنك ستتمكن من إنشاء وحدات تحكم ونماذج جديدة لهذا المحرك بسهولة بالغة عن طريق تشغيل الأوامر مثل:

$ bin/rails g model

ضع في اعتبارك، بالطبع، أن أي شيء يُنشأ باستخدام هذه الأوامر داخل المحرك يحتوي على isolate_namespace في صنف المحرك سيسمى.

دليل الاختبار

دليل test هو المكان الذي ستذهب إليه اختبارات المحرك. لاختبار المحرك، هناك نسخة مقطوعة من تطبيق Rails مضمنه في test/dummy. سيركب هذا التطبيق المحرك في ملف test / dummy / config / routes.rb:

Rails.application.routes.draw do

 mount Blorgh::Engine => "/blorgh"

End

يقوم هذا السطر بتثبيت المحرك على المسار / blorgh، مما يجعل الوصول إليه ممكناً من خلال التطبيق على هذا المسار فقط.

يوجد داخل دليل الاختبار دليل test/integration، حيث يجب وضع اختبارات التكامل للمحرك. يمكن إنشاء مجلدات أخرى في دليل test أيضًا. على سبيل المثال، قد ترغب في إنشاء دليل test/models لاختبارات نموذجك.

توفير وظائف المحرك

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

توليد مصادر المقال

أول شيء يُنشئ لمحرك المدونة هو نموذج Article ووحدة التحكم ذات الصلة. لتوليد ذلك بسرعة، يمكنك استخدام مولد سقالة Rails.

$ bin/rails generate scaffold article title:string text:text

سينتج هذا الأمر هذه المعلومات:

invoke  active_record

create    db/migrate/[timestamp]_create_blorgh_articles.rb

create    app/models/blorgh/article.rb

invoke    test_unit

create      test/models/blorgh/article_test.rb

create      test/fixtures/blorgh/articles.yml

invoke  resource_route

route    resources :articles

invoke  scaffold_controller

create    app/controllers/blorgh/articles_controller.rb

invoke    erb

create      app/views/blorgh/articles

create      app/views/blorgh/articles/index.html.erb

create      app/views/blorgh/articles/edit.html.erb

create      app/views/blorgh/articles/show.html.erb

create      app/views/blorgh/articles/new.html.erb

create      app/views/blorgh/articles/_form.html.erb

invoke    test_unit

create      test/controllers/blorgh/articles_controller_test.rb

invoke    helper

create      app/helpers/blorgh/articles_helper.rb

invoke  test_unit

create    test/application_system_test_case.rb

create    test/system/articles_test.rb

invoke  assets

invoke    js

create      app/assets/javascripts/blorgh/articles.js

invoke    css

create      app/assets/stylesheets/blorgh/articles.css

invoke  css

create    app/assets/stylesheets/scaffold.css

أولًا يستدعي مولد السقالة مولد active_record، الذي ينشئ الترحيل ونموذج للمصدر. ومع ذلك، لاحظ أن الترحيل يدعى Create_blorgh_articles بدلاً من create_articles المعتاد. هذا بسبب التابع isolate_namespace الذي يسمى في تعريف صنف Blorgh :: Engine. ويعتبر النموذج هنا ايضًا مساحة اسم، حيث يُوضع في app / models / blorgh / article.rb بدلاً من app / models / article.rb بسبب استدعاء isolate_namespace داخل صنف Engine.

بعد ذلك، يُستدعى مولد test_unit لهذا النموذج، مما يؤدي إلى اختبار النموذج في test / models / blorgh / article_test.rb (بدلاً من test/models/article_test.rb) و تثبيته في test/fixtures/blorgh/articles.yml ( بدلًا من test/fixtures/articles.yml).

بعد ذلك، يُدرج سطر للمصدر في ملف config / routes.rb للمحرك. هذا السطر هو ببساطة resources :articles، وتحويل ملف config / routes.rb للمحرك إلى هذا:

Blorgh::Engine.routes.draw do

 resources :articles

end

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

بعد ذلك، يستدعى مولد scaffold_controller، وتُولد وحدة تحكم تسمى Blorgh :: ArticlesController (في app/controllers/blorgh/articles_controller.rb) والواجهات ذات الصلة في app/views/blorgh/articles.

هذا المولد يولد أيضا اختبار لوحدة التحكم (test/controllers/blorgh/articles_controller_test.rb) والمساعد (app/helpers/blorgh/articles_helper.rb).

أُنشئ كل شيء أنشأه هذا المولد بدقة. وعُرفت صنف وحدة التحكم في وحدة Blorgh:

module Blorgh

 class ArticlesController < ApplicationController

   ...

 end

End

ملاحظة: ترث الصنف ArticlesController من Blorgh :: ApplicationController ، وليس التطبيق ApplicationController.

المساعد أيضا داخل app/helpers/blorgh/articles_helper.rb هو أيضا namespaced:

module Blorgh

 module ArticlesHelper

   ...

 end

End

يساعد ذلك على منع التعارضات مع أي محرك أو تطبيق آخر قد يكون له مصدر مقالة أيضًا.

وأخيرًا، يُنشأ أصول لهذا المصدر في ملفين: app / assets / javascripts / blorgh / articles.js و app / assets / stylesheets / blorgh / articles.css. سترى كيفية استخدام هذه في وقت لاحق قليلا.

إذا كنت تفضل اللعب في وحدة التحكم، فستعمل لوحة المفاتيح أيضًا مثل تطبيق Rails. تذكر: نموذج Article هو ذو أسماء، لذلك للإشارة إليه يجب أن تسميته كـ Blorgh :: Article.

>> Blorgh::Article.find(1)

=> #<Blorgh::Article id: 1 ...>

شيء واحد نهائي هو أن مصدر articles  لهذا المحرك يجب أن يكون هو جذر المحرك. عندما يذهب شخص ما إلى مسار الجذر حيث يُركب المحرك، يجب أن  يُعرض قائمة بالمقالات. يمكن إجراء ذلك إذا أُدرج هذا السطر في ملف config / routes.rb داخل المحرك:

root to: "articles#index"

الآن سيحتاج الناس فقط إلى جذر المحرك لرؤية جميع المقالات ، بدلاً من زيارة /articles. هذا يعني أنه بدلاً من http: // localhost: 3000 / blorgh / articles، ما عليك سوى الانتقال إلى http: // localhost: 3000 / blorgh الآن.

توليد مصدر التعليقات

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

من جذر التطبيق، شغل مولد النموذج. أخبره بإنشاء نموذج تعليق، مع الجدول ذي الصلة الذي به عمودين: عدد صحيح من article_id و text عمود نصي.

$ bin/rails generate model Comment article_id:integer text:text

هذا سوف يخرج ما يلي:

invoke  active_record

create    db/migrate/[timestamp]_create_blorgh_comments.rb

create    app/models/blorgh/comment.rb

invoke    test_unit

create      test/models/blorgh/comment_test.rb

create      test/fixtures/blorgh/comments.yml

سيولد هذا الاستدعاء فقط ملفات النماذج الضرورية التي تحتاجها، حيث تسمى الملفات تحت دليل blorgh وتُنشئ صنف نموذجية تسمى Blorgh :: Comment. الآن شغل الترحيل لإنشاء جدول blorgh_comments الخاص بنا:

$ bin/rails db:migrate

لإظهار التعليقات على إحدى المقالات، عدّل app/views/blorgh/articles/show.html.erb وأضف هذا السطر قبل رابط "التعديل":

<nowiki><h3>Comments</h3></nowiki>

<%= render @article.comments %>

سوف يتطلب هذا السطر أن يكون هناك رابطة has_many للتعليقات المحددة في النموذج Blorgh :: Article، والتي لا توجد الآن. لتحديد واحد، افتح app / models / blorgh / article.rb وأضف هذا السطر إلى النموذج:

has_many :comments

تحويل النموذج إلى هذا:

module Blorgh

 class Article < ApplicationRecord

   has_many :comments

 end

End

نظرًا لتمييز has_many داخل صنف موجودة داخل وحدة Blorgh، سيعرف Rails أنك تريد استخدام نموذج Blorgh :: Comment لهذه الكائنات، لذا لا داعي لتحديد ذلك باستخدام خيار: class_name هنا.

بعد ذلك، يجب أن يكون هناك نموذج حتى يمكن إنشاء التعليقات على المقالة. لإضافة هذا، ضع هذا السطر أسفل الدعوة لتقديم article.comments@ في app/views/blorgh/articles/show.html.erb:

<%= render "blorgh/comments/form" %>

التالى، جزئيًا أن هذا السطر سيجعل الاحتياجات موجودة. لإنشاء دليل جديد في app/views/blorgh/comments وفيه ملف جديد يسمى form.html.erb_ الذي يحتوي على هذا المحتوى لإنشاء الجزء المطلوب:

<nowiki><h3>New comment</h3></nowiki>

<%= form_with(model: [@article, @article.comments.build], local: true) do |form| %>

 <nowiki><p></nowiki>

   <%= form.label :text %><nowiki><br></nowiki>

   <%= form.text_area :text %>

 <nowiki></p></nowiki>

 <%= form.submit %>

<% end %>

عندما يرسل هذا النموذج، فإنه سيحاول تنفيذ طلب POST إلى المسار/articles/:article_id/comments داخل المحرك. هذا المسار غير موجود في الوقت الحالي، ولكن يُنشأ عن طريق تغيير سطر resources:articles داخل config / routes.rb إلى هذه السطور:

resources :articles do

 resources :comments

End

يؤدي هذا إلى إنشاء مسار متداخل للتعليقات، وهو ما يتطلبه النموذج.

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

$ bin/rails g controller comments

هذا سوف يولد الأشياء التالية:

create  app/controllers/blorgh/comments_controller.rb

invoke  erb

exist    app/views/blorgh/comments

invoke  test_unit

create    test/controllers/blorgh/comments_controller_test.rb

invoke  helper

create    app/helpers/blorgh/comments_helper.rb

invoke  assets

invoke    js

create      app/assets/javascripts/blorgh/comments.js

invoke    css

create      app/assets/stylesheets/blorgh/comments.css

سيقدم النموذج طلب POST إلى / articles /: article_id / comments، والتي تتوافق مع إجراء create في Blorgh :: CommentsController. يجب إنشاء هذا الإجراء، والذي يُنفذ عن طريق وضع السطور التالية داخل تعريف الصنف في app/controllers/blorgh/comments_controller.rb:

def create

 @article = Article.find(params[:article_id])

 @comment = @article.comments.create(comment_params)

 flash[:notice] = "Comment has been created!"

 redirect_to articles_path

end

private

 def comment_params

   params.require(:comment).permit(:text)

 End

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

<nowiki>Missing partial blorgh/comments/_comment with {:handlers=>[:erb, :builder],</nowiki>

<nowiki>:</nowiki>formats=>[:html], :locale=>[:en, :en]}. Searched in:   *

"/Users/ryan/Sites/side_projects/blorgh/test/dummy/app/views"   *

"/Users/ryan/Sites/side_projects/blorgh/app/views"

يتعذر على المحرك العثور على الجزء المطلوب لتقديم التعليقات. يبدو Rails أولاً في دليل التطبيق test/dummy) app/views) ثم في دليل app/views للمحرك. عندما لا يمكن العثور عليه، سوف يرمي هذا الخطأ. يعرف المحرك أن يبحث عن blorgh / comments / _comment لأن كائن النموذج الذي يستقبله هو من صنف Blorgh :: Comment.

ستكون هذه الجزئية مسؤولة عن تقديم نص التعليق فقط، في الوقت الحالي. أنشئ ملف جديد على app/views/blorgh/comments/_comment.html.erb وضع هذا السطر داخله:

<%= comment_counter + 1 %>. <%= comment.text %>

يعطي المتغير المحلي comment_counter بواسطة استدعاء <٪ = render

@ article.comments٪>، والتي ستحدده تلقائيًا وتزيد العداد أثناء تكرار كل تعليق. يُستخدم في هذا المثال لعرض رقم صغير بجوار كل تعليق عند إنشائه.

هذا يكمل وظيفة التعليق لمحرك التدوين. الآن حان الوقت لاستخدامها داخل التطبيق.

تركيبه في التطبيق

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

تركيب المحرك

أولاً، يجب تحديد المحرك داخل Gemfile الخاص بالتطبيق. إذا لم يكن هناك تطبيق مفيد لاختبار ذلك، فأنشئ تطبيقًا باستخدام الأمر rails new خارج دليل المشغل كما يلي:

$ rails new unicorn

عادة، يحدد المحرك داخل Gemfile من خلال تحديده كالمعتاد، جوهرة كل يوم.

gem 'devise'

ومع ذلك، نظرًا لأنك تقوم بتطوير محرك blorgh على جهازك المحلي، فستحتاج إلى تحديد خيار path: في Gemfile الخاص بك:

gem 'blorgh', path: 'engines/blorgh'

ثم شغل الحزمة لتثبيت الجوهرة.

كما هو موضح سابقًا، بوضع الجوهرة في Gemfile، سيحمل عند تحميل Rails. سيتطلب الأمر أولاً lib / blorgh.rb من المحرك، ثم lib / blorgh / engine.rb، وهو الملف الذي يحدد الأجزاء الرئيسية من الوظائف للمحرك.

لجعل وظيفة المحرك قابلة للوصول من داخل التطبيق، يجب تثبيته في ملف config / path.rb لهذا التطبيق:

mount Blorgh::Engine, at: "/blog"

سيقوم هذا السطر بتركيب المحرك على /blog  في التطبيق. مما يجعل الوصول إليها في http: // localhost: 3000 / blog عند تشغيل التطبيق مع rails server.

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

إعداد المحرك

يحتوي المحرك على عمليات ترحيل لجدول blorgh_articles و blorgh_comments والتي يلزم إنشاؤها في قاعدة بيانات التطبيق بحيث يمكن لنماذج المحرك الاستعلام عنها بشكل صحيح. لنسخ هذه الترحيلات إلى التطبيق،شغل الأمر التالي من دليل test/dummy الخاص بمحرك Rails:

$ bin/rails blorgh:install:migrations

إذا كان لديك العديد من المحركات التي تحتاج إلى نسخ عمليات الترحيل، استخدام railties:install:migrations  بدلاً من ذلك:

$ bin/rails railties:install:migrations

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

Copied migration [timestamp_1]_create_blorgh_articles.blorgh.rb from blorgh

Copied migration [timestamp_2]_create_blorgh_comments.blorgh.rb from blorgh

سيكون الطابع الزمني الأول ([timestamp_1]) هو الوقت الحالي، وسيكون الطابع الزمني الثاني ([timestamp_2]) هو الوقت الحالي بالإضافة إلى ثانية. السبب في ذلك هو أن تُشغل عمليات ترحيل المحرك بعد أي عمليات ترحيل حالية في التطبيق.

لتشغيل عمليات الترحيل هذه في سياق التطبيق، ما عليك سوى تشغيل bin/rails db:migrate. عند الوصول إلى المحرك من خلال http: // localhost: 3000 / blog، ستكون المقالات فارغة. وذلك لأن الجدول الذي أُنشأ داخل التطبيق يختلف عن الجدول الذي أُنشأ داخل المحرك. امضي قدما، للعلب مع المحرك الذي رُكب حديثا. ستجد أنه هو نفسه عندما كان مجرد محرك.

إذا كنت ترغب في تشغيل عمليات الترحيل فقط من محرك واحد، فيمكنك القيام بذلك عن طريق تحديد SCOPE:

bin/rails db:migrate SCOPE=blorgh

قد يكون هذا مفيدًا إذا كنت تريد التراجع عن عمليات ترحيل المحرك قبل إزالتها. لإعادة جميع عمليات الترحيل من محرك blorgh، يمكنك تشغيل كود مثل:

bin/rails db:migrate SCOPE=blorgh VERSION=0

باستخدام الصنف المقدمة من التطبيق

باستخدام نموذج مقدم من التطبيق

عندما يُنشأ المحرك، قد ترغب في استخدام فئات معينة من التطبيق لتوفير روابط بين أجزاء المحرك وأجزاء التطبيق. في حالة محرك blorgh، فإن كتابة المقالات والتعليقات تجعل المؤلفين منطقيين.

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

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

rails g model user name:string

يجب تشغيل الأمر bin / rails db: migrate هنا لضمان أن تطبيقنا يحتوي على جدول users للاستخدام في المستقبل.

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

أولاً، يجب إضافة حقل النص author_name إلىapp/views/blorgh/articles/_form.html.erb جزئيًا داخل المحرك. يمكن إضافة هذا فوق حقل title بهذا الكود:

<nowiki><div class="field"></nowiki>

 <%= form.label :author_name %><nowiki><br></nowiki>

 <%= form.text_field :author_name %>

<nowiki></div></nowiki>

بعد ذلك، نحتاج إلى تحديث التابع Blorgh :: ArticleController # article_params للسماح بمعامل النموذج الجديد:

def article_params

 params.require(:article).permit(:title, :text, :author_name)

end

يجب أن يحتوي نموذج Blorgh :: Article على رمز لتحويل حقل author_name إلى كائن User فعلي و إقرانه كـ author المقالة قبل حفظ المقالة. كما ستحتاج أيضًا إلى إعداد attr_accessor لهذا الحقل، بحيث تُحدد توابع الوضع والجلب الخاصة به.

للقيام بكل هذا، ستحتاج إلى إضافة attr_accessor لـ author_name، وربط المؤلف واستدعاء before_validation إلى app / models / blorgh / article.rb. سيرمز اقتران author لصنف User في الوقت الحاضر.

attr_accessor :author_name

belongs_to :author, class_name: "User"

before_validation :set_author

private

 def set_author

   self.author = User.find_or_create_by(name: author_name)

 end

من خلال تمثيل كائن رابطة author مع صنف المستخدم، ينشأ ارتباط بين المحرك والتطبيق. يجب أن تكون هناك طريقة لربط السجلات في جدول blorgh_articles بالسجلات في جدول المستخدمين. لأن الرابطة تستدعي author، يجب أن يكون هناك عمود author_id مضاف إلى جدول blorgh_articles.

لإنشاء هذا العمود الجديد، شغل هذا الأمر داخل المحرك:

$ bin/rails g migration add_author_id_to_blorgh_articles author_id:integer

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

يجب تشغيل هذا الترحيل على التطبيق. للقيام بذلك، يجب أولاً نسخها باستخدام هذا الأمر:

$ bin/rails blorgh:install:migrations

لاحظ أنه نُسخ ترحيل واحد فقط هنا. هذا لأن نُسخ أول ترحلين خلال المرة الأولى من تشغيل هذا الأمر.

NOTE Migration [timestamp]_create_blorgh_articles.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.

NOTE Migration [timestamp]_create_blorgh_comments.blorgh.rb from blorgh has been skipped. Migration with the same name already exists.

Copied migration [timestamp]_add_author_id_to_blorgh_articles.blorgh.rb from blorgh

شغّل الترحيل باستخدام:

$ bin/rails db:migrate

الآن مع كل القطع في مكانها، سيحدث إجراء يربط المؤلف - الذي يمثله سجل في جدول users- بمقال، ممثلة بجدول blorgh_articles من المحرك.

وأخيرًا، يجب أن يعرض اسم المؤلف على صفحة المقالة. أضف هذا الرمز فوق مخرج "العنوان" داخل app/views/blorgh/articles/show.html.erb:

<nowiki><p></nowiki>

 <nowiki><b>Author:</b></nowiki>

 <%= @article.author.name %>

<nowiki></p></nowiki>

استخدام وحدة التحكم المقدمة من التطبيق

نظرًا لأن وحدات تحكم Rails تشترك بشكل عام في التعليمات البرمجية لأشياء مثل الاستيثاق والوصول إلى متغيرات جلسة العمل، فإنها ترث من ApplicationController افتراضيًا.

محركات Rails، ومع ذلك يحدد نطاق للتشغيل بشكل مستقل عن التطبيق الرئيسي، بحيث يحصل كل محرك على نطاق ApplicationController.

تمنع مجال الاسم هذه تعارضات التعليمات البرمجية، ولكن غالباً ما تحتاج وحدات تحكم المحرك إلى الوصول إلى التوابع في ApplicationController التطبيق الرئيسي. إحدى الطرق السهلة لتوفير هذا الوصول هي تغيير ApplicationController الخاص بالمحرك إلى الوراثة من ApplicationController التطبيق الرئيسي. بالنسبة لمحرك Blorgh، يمكن القيام بذلك عن طريق تغيير app/controllers/blorgh/application_controller.rb لتبدو كما يلي:

module Blorgh

 class ApplicationController < ::ApplicationController

 end

End

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

يتطلب هذا التغيير تشغيل المحرك من تطبيق Rails يحتوي على ApplicationController.

إعداد تكوين المحرك

يغطي هذا القسم كيفية جعل صنف User قابلة للتكوين، متبوعة بنصائح تهيئة عامة للمحرك.

ضبط إعدادات التكوين في التطبيق

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

لتعريف إعداد التكوين هذا، يجب عليك استخدام mattr_accessor داخل وحدة Blorgh للمحرك. أضف هذا السطر إلى lib / blorgh.rb داخل المحرك:

mattr_accessor :author_class

يعمل هذا التابع مثل أشقائه، attr_accessor و cattr_accessor، ولكنه يوفر تابع setter و getter على النموذج بالاسم المحدد. لاستخدامها، يجب الإشارة إليها باستخدام Blorgh.author_class.

الخطوة التالية هي تبديل نموذج Blorgh :: Article إلى هذا الإعداد الجديد. غير الارتباط belongs_to داخل هذا النموذج (app/models/blorgh/article.rb) لهذا:

belongs_to :author, class_name: Blorgh.author_class

يجب أيضًا أن يستخدم التابع set_author في نموذج Blorgh :: Article هذه الصنف:

self.author = Blorgh.author_class.constantize.find_or_create_by(name: author_name)

لحفظ الحاجة إلى استدعاء ثابت على نتيجة author_class طوال الوقت، يمكنك بدلاً من ذلك فقط تجاوز التابع getter_class author_class داخل وحدة Blorgh في ملف lib / blorgh.rb لتستدعي دائمًا constantize على القيمة المحفوظة قبل إرجاع النتيجة:

def self.author_class

 @@author_class.constantize

End

سيؤدي هذا بعد ذلك إلى تحويل الرمز أعلاه إلى set_author في هذا:

self.author = Blorgh.author_class.find_or_create_by(name: author_name)

مما يؤدي إلى شيء أقصر قليلا، و مضمنه اكثر في سلوكها. يجب دائمًا إرجاع التابع author_class الكائن Class.

بما أننا غيرنا التابع author_class لإرجاع صنف بدلاً من سلسلة، فيجب علينا أيضًا تعديل تعريف belongs_to الخاص بنا في نموذج Blorgh :: Article:

belongs_to :author, class_name: Blorgh.author_class.to_s

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

إنشاء مُهيئ جديد في config / initializers / blorgh.rb داخل التطبيق حيث رُكب المحرك blorgh ووضع هذا المحتوى فيه:

Blorgh.author_class = "User"

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

امضي قدما وحاول إنشاء مقال جديد. سترى أنه يعمل بالضبط بنفس الطريقة كما كان من قبل، ما عدا هذا الوقت يستخدم المحرك إعداد التكوين في config / initializers / blorgh.rb لمعرفة ما هي الصنف.

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

إعداد تكوين المحرك العام

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

إذا كنت ترغب في استخدام مُهيئ -  يجب أن يشغل الكود قبل تحميل المحرك - فإن مكانه هو مجلد config / initializers. وضح وظيفة هذا الدليل في قسم Initializers من دليل التوصيف، وتعمل بنفس الطريقة بالضبط مثل دليل config / initializers داخل التطبيق. نفس الشيء إذا كنت تريد استخدام مُهيئ قياسي.

محليًا، ضع ببساطة ملفات الإعدادات المحلية في دليل config / locales، تمامًا كما تفعل في التطبيق.

اختبار المحرك

عند إنشاء المحرك، هناك تطبيق وهمي أصغر ينشئ داخله في test/dummy. يستخدم هذا التطبيق كنقطة تثبيت للمحرك، لجعل اختبار المحرك بسيط للغاية. يمكنك تمديد هذا التطبيق عن طريق توليد وحدات تحكم أو نماذج أو واجهات من داخل الدليل، ثم استخدمها لاختبار محركك.

يجب معاملة دليل test مثل بيئة اختبار Rails النموذجية، مما يسمح باختبارات الوحدة والوظيفة والتكامل.

الاختبارات الوظيفية

هناك مسألة تستحق الأخذ في الاعتبار عند كتابة الاختبارات الوظيفية وهي أن الاختبارات ستعمل على تطبيق - تطبيق test/dummy- بدلاً من المحرك الخاص بك. هذا بسبب إعداد بيئة الاختبار؛ يحتاج المحرك إلى تطبيق كمضيف لاختبار وظائفه الرئيسية، وخاصة أجهزة التحكم. هذا يعني أنه إذا كنت ستجعل GET نموذجية إلى وحدة التحكم في اختبار وظيفية وحدة تحكم مثل هذا:

module Blorgh

 class FooControllerTest < ActionDispatch::IntegrationTest

   include Engine.routes.url_helpers

   def test_index

     get foos_url

     ...

   end

 end

End

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

module Blorgh

 class FooControllerTest < ActionDispatch::IntegrationTest

   include Engine.routes.url_helpers

   setup do

     @routes = Engine.routes

   end

   def test_index

     get foos_url

     ...

   end

 end

end

هذا يخبر التطبيق أنك لا تزال ترغب في تنفيذ طلب GET إلى إجراء index لوحدة التحكم هذه، ولكنك تريد استخدام مسار المحرك للوصول إلى هناك، بدلاً من مسار التطبيق.

يضمن هذا أيضًا أن تعمل أدوات مساعدة عنوان URL الخاصة بالمحرك كما هو متوقع في اختباراتك.

تحسين وظائف المحرك

يشرح هذا القسم كيفية إضافة و / أو تجاوز وظائف نموذج MVC للمحرك في تطبيق Rails الرئيسي.

تجاوز النماذج ووحدات التحكم

توسع فئات المحرك ونموذج وحدة التحكم عن طريق فتحها في تطبيق Rails الرئيسي (نظرًا لأن فئات النموذج ووحدة التحكم ليست سوى فئات Ruby التي ترث وظيفة معينة في Rails). فتح تصنيف صنف المحرك يعيد تعريفه للاستخدام في التطبيق الرئيسي. تنفذ ذلك عادةً باستخدام نمط الديكور.

بالنسبة لتعديلات صنف بسيطة، استخدم Class # class_eval. لتعديلات صنف معقدة، ضع في اعتبارك استخدام ActiveSupport :: Concern.

ملاحظة حول Decorators و Code Loading

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

إليك بعض نماذج الكود للقيام بذلك:

<nowiki>#</nowiki> lib/blorgh/engine.rb

module Blorgh

 class Engine < ::Rails::Engine

   isolate_namespace Blorgh

   config.to_prepare do

     Dir.glob(Rails.root + "app/decorators/**/*_decorator*.rb").each do |c|

       require_dependency(c)

     end

   end

 end

End

هذا لا ينطبق فقط على Decorators، ولكن أي شيء تضيفه في محرك لا يشار إليه بواسطة التطبيق الرئيسي.

تنفيذ نمط Decorator باستخدام  Class # class_eval

إضافة Article#time_since_created:

<nowiki>#</nowiki> MyApp/app/decorators/models/blorgh/article_decorator.rb

Blorgh::Article.class_eval do

 def time_since_created

   Time.current - created_at

 end

End

<nowiki>#</nowiki> Blorgh/app/models/article.rb

class Article < ApplicationRecord

 has_many :comments

End

تجاوز Article#summary:

<nowiki>#</nowiki> MyApp/app/decorators/models/blorgh/article_decorator.rb

Blorgh::Article.class_eval do

 def summary

   "#{title} - #{truncate(text)}"

 end

End

<nowiki>#</nowiki> Blorgh/app/models/article.rb

class Article < ApplicationRecord

 has_many :comments

 def summary

   "#{title}"

 end

end

تنفيذ نمط المصمم باستخدام ActiveSupport::Concern

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

إضافة Article#time_since_created وتجاوز Article#summary:

<nowiki>#</nowiki> MyApp/app/models/blorgh/article.rb

class Blorgh::Article < ApplicationRecord

 include Blorgh::Concerns::Models::Article

 def time_since_created

   Time.current - created_at

 end

 def summary

   "#{title} - #{truncate(text)}"

 end

End

<nowiki>#</nowiki> Blorgh/app/models/article.rb

class Article < ApplicationRecord

 include Blorgh::Concerns::Models::Article

End

<nowiki>#</nowiki> Blorgh/lib/concerns/models/article.rb

module Blorgh::Concerns::Models::Article

 extend ActiveSupport::Concern

 # 'included do' causes the included code to be evaluated in the

 # context where it is included (article.rb), rather than being

 # executed in the module's context (blorgh/concerns/models/article).

 included do

   attr_accessor :author_name

   belongs_to :author, class_name: "User"

    before_validation :set_author

   private

     def set_author

       self.author = User.find_or_create_by(name: author_name)

     end

 end

 def summary

   "#{title}"

 end

  module ClassMethods

   def some_class_method

     'some class method string'

   end

 end

end

تجاوز الواجهات

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

عندما يُطلب من التطبيق تقديم واجهة لإجراء مؤشر Blorgh :: ArticlesController، سيبحث أولاً عن المسار app/views/blorgh/articles/index.html.erb ضمن التطبيق. إذا لم تتمكن من العثور عليه، فسيظهر داخل المحرك.

يمكنك تجاوز هذه الواجهة في التطبيق ببساطة عن طريق إنشاء ملف جديد في app/views/blorgh/articles/index.html.erb. بعد ذلك، يمكنك تغيير طريقة عرض هذه الواجهة تمامًا.

جرب هذا الآن عن طريق إنشاء ملف جديد في app/views/blorgh/articles/index.html.erb ووضع هذا المحتوى فيه:

<nowiki><h1>Articles</h1></nowiki>

<%= link_to "New Article", new_article_path %>

<% @articles.each do |article| %>

 <nowiki><h2><%= article.title %></h2></nowiki>

 <nowiki><small>By <%= article.author %></small></nowiki>

 <%= simple_format(article.text) %>

 <nowiki><hr></nowiki>

<% end %>

المسارات

تعزل المسارات داخل المحرك من التطبيق بشكل افتراضي. وذلك عن طريق استدعاء isolate_namespace داخل صنف Engine. وهذا يعني بالضرورة أن التطبيق ومحركاته يمكن أن يكون لهما مسارات مسماة بشكل مماثل ولن يتعارضان.

ترسم المسارات داخل المحرك في صنف المحرك داخل config / routes.rb، على النحو التالي:

Blorgh::Engine.routes.draw do

 resources :articles

End

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

على سبيل المثال، سيذهب المثال التالي إلى article_path للتطبيق إذا عُرض هذا القالب من التطبيق، أو article_path الخاص بالمحرك إذا عُرض من المحرك:

<%= link_to "Blog articles", articles_path %>

ولجعل هذا المسار دائمًا يستخدم تابع مساعد التوجيه article_path للمحرك، يجب علينا استدعاء التابع على تابع بروكسي التوجيه الذي يشترك في نفس اسم المحرك.

<%= link_to "Blog articles", blorgh.articles_path %>

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

<%= link_to "Home", main_app.root_path %>

إذا كنت تستخدم هذا داخل المحرك، فإنه سوف يذهب دائما إلى جذر التطبيق. إذا كنت ستترك استدعاء تابع "بروكسي التوجيه" main_app، فمن المحتمل أن تذهب إلى جذر المحرك أو التطبيق، حسب المكان الذي اتصل به منه.

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

الأصول

تعمل الأصول داخل المحرك بطريقة مماثلة لتطبيق كامل. نظرًا لأن صنف المحرك ترث من Rails :: Engine، سيعرف التطبيق البحث عن الأصول في المحرك app/assets والمجلدات  lib/assets.

مثل جميع المكونات الأخرى للمحرك، يجب أن تكون الأصول ذات تسميات. وهذا يعني أنه إذا كان لديك اصل يسمى style.css، فيجب وضعه في app/assets/stylesheets/[engine name]/style.css، بدلاً من app/assets/stylesheets/style.css. إذا لم يكن الأصل هذا يحمل أسماء، فمن المحتمل أن يكون لدى التطبيق المضيف أصل مسمى بشكل مطابق، وفي هذه الحالة يكون لأصل التطبيق الأولوية و سيتجاهل المحرك.

تخيل أن لديك أصل موجود في app/assets/stylesheets/blorgh/style.css لتضمين الأصل هذا داخل أحد التطبيقات، ما عليك سوى استخدام stylesheet_link_tag والإشارة إلى الأصل كما لو كان داخل المحرك:

<%= stylesheet_link_tag "blorgh/style.css" %>

يمكنك أيضًا تحديد هذه الأصول باعتبارها تبعيات للإصول الأخرى باستخدام Asset Pipeline تتطلب جمل في الملفات التي تمت معالجتها:

/*

<nowiki>*</nowiki>= require blorgh/style

<nowiki>*</nowiki>/

ملاحظة: تذكر أنه من أجل استخدام لغات مثل Sass أو CoffeeScript، يجب عليك إضافة المكتبة ذات الصلة إلى gemspec. الخاص بالمحرك.

الأصول المنفصلة و Precompiling

هناك بعض الحالات التي لا يتطلب فيها التطبيق المضيف أصول محركك. على سبيل المثال، لنفترض أنك أنشأت وظيفة مسؤول لا تتوفر إلا لمحركك. في هذه الحالة، لا يحتاج التطبيق المضيف إلى طلب admin.css أو admin.js. يحتاج تخطيط المشرف فقط إلى هذه الأصول. من غير المعقول أن يتضمن التطبيق المضيف "blorgh / admin.css" في صفحات الأنماط الخاصة به. في هذه الحالة، يجب أن تُعرف هذه الأصول بشكل واضح من أجل التحويل المسبق. هذا يخبر Sprockets لإضافة أصول المحرك الخاص بك عند تشغيل bin/rails assets:precompile.

يمكنك تعريف الأصول للتحليل المسبق في engine.rb:

initializer "blorgh.assets.precompile" do |app|

 app.config.assets.precompile += %w( admin.js admin.css )

End

لمزيد من المعلومات، اقرأ دليل الأصول pipeline.

تبعيات الجوهرة الاخرى

يجب تحديد تبعيات Gem داخل المحرك داخل ملف gemspec. في جذر المحرك. والسبب هو أن المحرك قد يركب كجوهرة. إذا كان من المقرر تحديد التبعيات داخل Gemfile، فلن يتعرف عليها من خلال تثبيت جوهرة تقليدية وبالتالي لن تُثبت، مما يؤدي إلى خلل في المحرك.

لتحديد تبعية يجب تثبيتها مع المحرك أثناء gem install التقليدية، عينها داخل كتلة Gem :: Specification الموجودة داخل الملف gemspec. في المحرك:

s.add_dependency "moo"

لتحديد تبعية لا يجب تثبيتها إلا كإعتماد على تطوير التطبيق، تُعين على النحو التالي:

s.add_development_dependency "moo"

تُثبت كلا النوعين من التبعيات عند تشغيل bundle install داخل التطبيق. لن يستخدم تبعيات التطوير للجوهرة إلا عند تشغيل اختبارات المحرك.

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

require 'other_engine/engine'

require 'yet_another_engine/engine'

module MyEngine

 class Engine < ::Rails::Engine

 end

End

الدعم النشط لتحميل التركيب

الدعم النشط هو مكون Ruby on Rails المسؤول عن توفير ملحقات اللغة Ruby والأدوات المساعدة والأدوات المستعرضة الأخرى.

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

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

ما هي خطافات on_load ؟

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

ActiveRecord::Base.include(MyActiveRecordHelper)

يعني هذا المقتطف أنه عند تحميل هذا الملف، سيواجه ActiveRecord :: Base. تؤدي هذه المواجهة إلى قيام روبي بالبحث عن تعريف هذا الثابت وسيتطلب فعل ذلك. يؤدي هذا لتحميل إطار Active Record  بالكامل في التمهيد.

ActiveSupport.on_load هي آلية يمكن استخدامها لتأجيل تحميل الشفرة إلى أن تكون ضرورية بالفعل. يمكن تغيير المقتطف أعلاه إلى:

ActiveSupport.on_load(:active_record) { include MyActiveRecordHelper }

يتضمن هذا المقتطف الجديد MyActiveRecordHelper فقط عند تحميل ActiveRecord :: Base.

كيف يعمل؟

في إطار Rails تُستدعى هذه الخطافات عند تحميل مكتبة معينة. على سبيل المثال، عند تحميل ActionController :: Base، تُستدعى hook: action_controller_base. هذا يعني أن جميع الاستدعاءات ActiveSupport.on_load مع خطافات  action_controller_base: تستدعى في سياق ActionController :: Base (وهذا يعني أن self سوف يكون ActionController :: Base).

تعديل التعليمات البرمجية لاستخدام on_load hooks

تعديل التعليمات بشكل عام بسيط. إذا كان لديك سطر من التعليمات البرمجية يشير إلى إطار Rails مثل ActiveRecord :: Base يمكنك التفاف ذلك الرمز في خطاف on_load.

مثال 1

ActiveRecord::Base.include(MyActiveRecordHelper)

يصبح

ActiveSupport.on_load(:active_record) { include MyActiveRecordHelper }

<nowiki>#</nowiki>self تشير إلى ActiveRecord :: Base هنا، لذلك يمكننا ببساطة # تضمينها.

=== مثال 2 ===
<syntaxhighlight lang="rails">
ActionController::Base.prepend(MyActionControllerHelper)

يصبح

ActiveSupport.on_load(:action_controller_base) { prepend MyActionControllerHelper }

Self تُشير إلى ActionController :: Base هنا، لذلك يمكننا ببساطة #prepend.

=== مثال 3 ===
<syntaxhighlight lang="rails">
ActiveRecord::Base.include_root_in_json = true

يصبح

ActiveSupport.on_load(:active_record) { self.include_root_in_json = true }

يشير self إلى ActiveRecord :: Base هنا.

الخطافات المتاحة

هذه هي الخطافات التي يمكنك استخدامها في التعليمات البرمجية الخاصة بك.

للربط في عملية التهيئة لإحدى الفئات التالية استخدم الخطاف المتوفر.

الصنف الخطاف المتاح
ActionCable action_cable
ActionController::API action_controller_api
ActionController::API action_controller
     ActionController::Base action_controller_base
     ActionController::Base action_controller
  ActionController::TestCase action_controller_test_case
      ActionDispatch::IntegrationTest action_dispatch_integration_test
    ActionDispatch::SystemTestCase action_dispatch_system_test_case
ActionMailer::Base action_mailer
   ActionMailer::TestCase action_mailer_test_case
ActionView::Base action_view
ActionView::TestCase action_view_test_case
ActiveJob::Base active_job
ActiveJob::TestCase active_job_test_case
ActiveRecord::Base active_record
ActiveSupport::TestCase active_support_test_case
i18n i18n

إعداد تكوين الخطافات

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

الخطاف حالة الاستخدام
before_configuration تشغيل أول كتلة قابلة للتكوين. تُستدعى قبل أي تمهيد.
    before_initialize تشغيل ثاني كتلة قابلة للتكوين. تُستدعى قبل تهيئة الأطر.
   before_eager_load تشغيل ثالث كتلة قابلة للتكوين. لا يعمل إذا كان config.eager_load مضبوطًا على false.
after_initialize تشغيل آخر كتلة قابلة لتكوين. تُستدعى بعد تهيئة الأطر.

مثال

Config.before_configuration { puts 'I am called before any initializers' }

مصادر