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

من موسوعة حسوب
إنشاء الصفحة. هذه الصفحة من مساهمات "دعاء فرح"
 
طلا ملخص تعديل
 
(2 مراجعات متوسطة بواسطة نفس المستخدم غير معروضة)
سطر 7: سطر 7:
* كيفية بحث ريلز عن المولدات قبل استدعائها.
* كيفية بحث ريلز عن المولدات قبل استدعائها.
* كيفية إنشاء ريلز داخليًا شيفرة من القوالب.
* كيفية إنشاء ريلز داخليًا شيفرة من القوالب.
* كيفية تخصيص المنصة الخاصة بك (scaffold) عن طريق إنشاء مولدات جديدة.
* كيفية تخصيص المولد scaffold عن طريق إنشاء مولدات جديدة.
* كيفية تخصيص المنصة الخاصة بك (scaffold) عن طريق تغيير قوالب المولدات.
* كيفية تخصيص المولد scaffold عن طريق تغيير قوالب المولدات.
* كيفية استخدام التراجعات (fallbacks) لتجنب استبدال مجموعة ضخمة من المولدات.
* كيفية استخدام التراجعات (fallbacks) لتجنب استبدال مجموعة ضخمة من المولدات.
* كيفية إنشاء قالب التطبيق.
* كيفية إنشاء قالب التطبيق.
سطر 14: سطر 14:
== الاتصال الأول ==
== الاتصال الأول ==
عندما تنشئ تطبيقًا باستخدام الأمر <code>rails</code>، فأنت في الحقيقة تستخدم مولد ريلز. بعد ذلك، يمكنك الحصول على قائمة بجميع المولدات المتاحة عن طريق استدعاء <code>rails generate</code> فقط:
عندما تنشئ تطبيقًا باستخدام الأمر <code>rails</code>، فأنت في الحقيقة تستخدم مولد ريلز. بعد ذلك، يمكنك الحصول على قائمة بجميع المولدات المتاحة عن طريق استدعاء <code>rails generate</code> فقط:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ rails new myapp
$ rails new myapp
$ cd myapp
$ cd myapp
$ bin/rails generate
$ bin/rails generate
</syntaxhighlight>
</syntaxhighlight>


سوف تحصل على قائمة بجميع المولدات التي تأتي مع Rails. إذا كنت بحاجة إلى وصف تفصيلي لمولد المساعد، على سبيل المثال، يمكنك ببساطة القيام بما يلي:
سوف تحصل على قائمة بجميع المولدات التي تأتي مع ريلز. إذا كنت بحاجة إلى وصف تفصيلي لمولد المساعد، على سبيل المثال، يمكنك ببساطة القيام بما يلي:<syntaxhighlight lang="shell">
 
$ bin/rails generate helper --help
$ bin/rails generate helper --help
</syntaxhighlight>


== إنشاء المولد الأول الخاص بك ==
== إنشاء المولد الأول الخاص بك ==
منذ Rails 3.تنشأ المولدات أعلى Thor. يوفر Thor خيارات قوية للتحليل وواجهة برمجة تطبيقات رائعة لمعالجة الملفات. على سبيل المثال، لإنشاء مولد ننشئ ملف مُهيئ يسمى initializer.rb داخل config / initializers.
منذ الإصدار 3.0 من ريلز، تنشأ المولدات أعلى [https://github.com/erikhuda/thor Thor]. يوفر [https://github.com/erikhuda/thor Thor] خيارات قوية للتحليل، وواجهة برمجة تطبيقات رائعة لمعالجة الملفات. على سبيل المثال، لإنشاء مولد ينشئ ملف مُهيئ يسمى initializer.rb داخل config/initializers.


الخطوة الأولى هي إنشاء ملف في lib / generators / initializer_generator.rb بالمحتوى التالي:
الخطوة الأولى هي إنشاء ملف في lib/generators/initializer_generator.rb بالمحتوى التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
class InitializerGenerator < Rails::Generators::Base
class InitializerGenerator < Rails::Generators::Base
 
  def create_initializer_file
 def create_initializer_file
    create_file "config/initializers/initializer.rb", "# Add initialization content here"
 
  end
   create_file "config/initializers/initializer.rb", "# Add initialization content here"
end
 
 end
 
End
</syntaxhighlight>
</syntaxhighlight>


ملاحظة: create_file هو تابع مقدم من Thor :: Actions. يمكن العثور على وثائق لـ create_file وطرق Thor الأخرى في وثائق Thor.
'''ملاحظة''': <code>create_file</code> هو تابع مقدم من <code>Thor::Actions</code>. يمكن العثور على توثيق للتابع <code>create_file</code> وتوابع Thor الأخرى في [http://rdoc.info/github/erikhuda/thor/master/Thor/Actions.html توثيق Thor].


مولدنا الجديد بسيط للغاية: فهو يرث من Rails :: Generators :: Base وله تعريف واحد للتابع. عندما يُستدعى مولد، يُنفذ كل تابع عام في المولد بالترتيب التسلسلي الذي عُرف به. وأخيرًا، نستدعي تابع create_file التي ستنشئ ملفًا في الوجهة المحددة بالمحتوى المحدد. إذا كنت معتادًا على  قوالب API لتطبيق Rails، فستشعر وكأنك في المنزل باستخدام واجهة برمجة التطبيقات للمولدات الجديدة.
مولدنا الجديد بسيط للغاية: فهو يرث من <code>Rails::Generators::Base</code> وله تعريف واحد للتابع. عندما يُستدعَى المولد، يُنفذ كل تابع عام في المولد بالترتيب التسلسلي الذي عُرِّف به. وأخيرًا، نستدعي التابع <code>create_file</code> الذي سينشئ ملفًا في الوجهة المحددة بالمحتوى المحدد. إذا كنت معتادًا على  قوالب الواجهة البرمجية (API) لتطبيق ريلز، فستشعر بشيء من الألفة عند استخدام واجهة برمجة التطبيقات للمولدات الجديدة.


لاستدعاء المولد الجديد، نحتاج فقط إلى القيام بما يلي:
لاستدعاء المولد الجديد، نحتاج فقط إلى القيام بما يلي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate initializer
$ bin/rails generate initializer
</syntaxhighlight>
</syntaxhighlight>


قبل أن نبدأ، لنرى وصف علامة المولد الجديد:
قبل أن نبدأ، لنرى وصف علامة المولد الجديد:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate initializer --help
$ bin/rails generate initializer --help
</syntaxhighlight>
</syntaxhighlight>


Rails عادة ما تكون قادرة على توليد أوصاف جيدة إذا كان المولّد هو namespaced، مثل
ريلز عادةً ما تكون قادرة على توليد أوصاف جيدة إذا كان المولّد هو مجال اسم، مثل


ActiveRecord :: Generators :: ModelGenerator، ولكن ليس في هذه الحالة بالذات. يمكننا حل هذه المشكلة بطريقتين. أول واحد هو استدعاء desc داخل مولدنا:
<code>ActiveRecord::Generators::ModelGenerator</code>، ولكن ليس في هذه الحالة بالذات. يمكننا حل هذه المشكلة بطريقتين. الحل الأول هو استدعاء <code>desc</code> داخل مولدنا:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
class InitializerGenerator < Rails::Generators::Base
class InitializerGenerator < Rails::Generators::Base
 
  desc "This generator creates an initializer file at config/initializers"
 desc "This generator creates an initializer file at config/initializers"
  def create_initializer_file
 
    create_file "config/initializers/initializer.rb", "# Add initialization content here"
 def create_initializer_file
  end
 
end
   create_file "config/initializers/initializer.rb", "# Add initialization content here"
 
 end
 
End
</syntaxhighlight>
</syntaxhighlight>


الآن يمكننا رؤية الوصف الجديد من خلال استدعاء --help على المولد الجديد. الطريقة الثانية لإضافة وصف هي عن طريق إنشاء ملف يسمى USAGE في نفس الدليل كمولدنا. سنقوم بذلك في الخطوة التالية.
الآن يمكننا رؤية الوصف الجديد من خلال استدعاء ‎<code>--help</code> على المولد الجديد. الطريقة الثانية لإضافة وصف هي عن طريق إنشاء ملف يسمى USAGE في نفس المجلد الموجود فيه مولدنا. سنقوم بذلك في الخطوة التالية.


== إنشاء مولدات مع المولدات ==
== إنشاء مولدات مع المولدات ==
المولدات نفسها لديها مولد:
المولدات نفسها لديها مولد:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate generator initializer
$ bin/rails generate generator initializer
 
      create  lib/generators/initializer
     create  lib/generators/initializer
      create  lib/generators/initializer/initializer_generator.rb
 
      create  lib/generators/initializer/USAGE
     create  lib/generators/initializer/initializer_generator.rb
      create  lib/generators/initializer/templates
 
      invoke  test_unit
     create  lib/generators/initializer/USAGE
      create    test/lib/generators/initializer_generator_test.rb
 
     create  lib/generators/initializer/templates
 
     invoke  test_unit
 
     create    test/lib/generators/initializer_generator_test.rb
</syntaxhighlight>
</syntaxhighlight>


هذا هو المولد الذي أُنشأ للتو:
هذا هو المولد الذي أُنشأ للتو:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
class InitializerGenerator < Rails::Generators::NamedBase
class InitializerGenerator < Rails::Generators::NamedBase
 
  source_root File.expand_path('templates', __dir__)
 source_root File.expand_path('templates', __dir__)
end
 
End
</syntaxhighlight>
</syntaxhighlight>


أولاً، لاحظ أننا نرث من Rails :: Generators :: NamedBase بدلاً من Rails :: Generators :: Base. هذا يعني أن مولدنا يتوقع حجة واحدة على الأقل، والتي ستكون اسم المُهيئ، وستكون متاحة في الكود الخاص بنا في المتغير name.
أولًا، لاحظ أننا نرث من <code>Rails::Generators::NamedBase</code> بدلًا من <code>Rails::Generators::Base</code>. هذا يعني أن مولدنا يتوقع وسيطًا واحدًا على الأقل، والذي سيكون اسم المُهيئ، وسيكون متاحًا في الشيفرة الخاص بنا في المتغير <code>name</code>.


يمكننا أن نرى ذلك من خلال استدعاء وصف هذا المولد الجديد (لا تنس حذف ملف المولد القديم):
يمكننا أن نرى ذلك من خلال استدعاء وصف هذا المولد الجديد (لا تنس حذف ملف المولد القديم):
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate initializer --help
$ bin/rails generate initializer --help
Usage:
Usage:
 
  rails generate initializer NAME [options]
 rails generate initializer NAME [options]
</syntaxhighlight>
</syntaxhighlight>


يمكننا أيضًا رؤية أن المولد الجديد لديه تابع صنف يُسمى source_root. يشير هذا التابع إلى مكان وضع قوالب المولد الخاصة بنا، إن وجدت، وبشكل افتراضي يشير إلى الدليل الذي أُنشأ lib/generators/initializer/templates.
يمكننا أيضًا رؤية أن المولد الجديد لديه تابع صنف يُسمى <code>source_root</code>. يشير هذا التابع إلى مكان وضع قوالب المولد الخاصة بنا، إن وجدت، وبشكل افتراضي يشير إلى المجلد lib/generators/initializer/templates الذي أُُنشِئ.


لفهم معنى قالب المولد، نُنشأ الملف lib/generators/initializer/templates/initializer.rb بالمحتوى التالي:
لفهم معنى قالب المولد، نُنشئ الملف lib/generators/initializer/templates/initializer.rb بالمحتوى التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<nowiki>#</nowiki> Add initialization content here
# Add initialization content here
</syntaxhighlight>
</syntaxhighlight>


سطر 123: سطر 102:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
class InitializerGenerator < Rails::Generators::NamedBase
class InitializerGenerator < Rails::Generators::NamedBase
 
  source_root File.expand_path('templates', __dir__)
 source_root File.expand_path('templates', __dir__)
 
  def copy_initializer_file
 def copy_initializer_file
    copy_file "initializer.rb", "config/initializers/#{file_name}.rb"
 
  end
   copy_file "initializer.rb", "config/initializers/#{file_name}.rb"
end
 
 end
 
End
</syntaxhighlight>
</syntaxhighlight>


دعنا ننفذه على المولد الخاص بنا:
دعنا ننفذه على المولد الخاص بنا:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate initializer core_extensions
$ bin/rails generate initializer core_extensions
</syntaxhighlight>
</syntaxhighlight>


يمكننا أن نرى أنه أُنشأ مُهيئ باسم core_extensions في config / initializers / core_extensions.rb بمحتويات القالب الخاص بنا. وهذا يعني أن copy_file نسخ الملف في المصدر الأصل الخاص بنا إلى مسار الوجهة الذي قدمناه. ينشئ التابع file_name تلقائيًا عندما نرث من Rails :: Generators :: NamedBase.
يمكننا أن نرى أنه أُنشئ مُهيئ باسم <code>core_extensions</code> في config/initializers/core_extensions.rb بمحتويات القالب الخاص بنا. وهذا يعني أن <code>copy_file</code> نسخ الملف في المصدر الأصل الخاص بنا إلى مسار الوجهة الذي قدمناه. يُنشَأ التابع <code>file_name</code> تلقائيًا عندما نرث من <code>Rails::Generators::NamedBase</code>.


تُغطى التوابع المتوفرة للمولدات في القسم الأخير من هذا الدليل.
سنشير إلى التوابع المتوفرة للمولدات في [[Rails/generators#.D8.AA.D9.88.D8.A7.D8.A8.D8.B9 .D8.A7.D9.84.D9.85.D9.88.D9.84.D8.AF|القسم الأخير]] من هذا الدليل.


== بحث المولدات ==
== البحث عن مولدات ==
عند تشغيل rails generate initializer core_extensions تتطلب Rails هذه الملفات بدورها حتى تعثر على أحدها:
عند تشغيل <code>rails generate initializer core_extensions</code> تتطلب ريلز هذه الملفات بدورها حتى تعثر على أحدها:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="text">
rails/generators/initializer/initializer_generator.rb
rails/generators/initializer/initializer_generator.rb
generators/initializer/initializer_generator.rb
generators/initializer/initializer_generator.rb
rails/generators/initializer_generator.rb
rails/generators/initializer_generator.rb
generators/initializer_generator.rb
generators/initializer_generator.rb
</syntaxhighlight>
</syntaxhighlight>


إذا لم يعثر على أي شيء، فسيتلقى رسالة خطأ.
إذا لم يعثر على أي شيء، فستُعرَض رسالة خطأ.


ملاحظة: الأمثلة أعلاه وضع الملفات تحت تطبيق lib لأن الدليل المذكور ينتمي إلى $ LOAD_PATH.
'''ملاحظة''': تضع الأمثلة أعلاه الملفات تحت تطبيق <code>lib</code> لأن المجلد المذكور ينتمي إلى ‎<code>$LOAD_PATH</code>.


== تخصيص سير العمل الخاص بك ==
== تخصيص سير العمل الخاص بك ==
المولدات الخاصة بـ Rails مرنة بما يكفي لتسمح لك بتخصيص السقالات. يمكن تكوينها في config / application.rb، هذه بعض الافتراضات:
المولدات الخاصة بريلز مرنة بما يكفي لتسمح لك بتخصيص السقالات (scaffolding). يمكن ضبطها في config/application.rb، هذه بعض الافتراضات:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
 
  g.orm             :active_record
 g.orm             :active_record
  g.template_engine :erb
 
  g.test_framework :test_unit, fixture: true
 g.template_engine :erb
end
 
 g.test_framework  :test_unit, fixture: true
 
End
</syntaxhighlight>
</syntaxhighlight>


قبل تخصيص سير العمل الخاص بنا، لنرى أولاً الشكل الذي تبدو عليه سقالاتنا:
قبل تخصيص سير العمل الخاص بنا، لنرى أولًا الشكل الذي تبدو عليه سقالاتنا (scaffold):
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate scaffold User name:string
$ bin/rails generate scaffold User name:string
 
      invoke  active_record
     invoke  active_record
      create    db/migrate/20130924151154_create_users.rb
 
      create    app/models/user.rb
     create    db/migrate/20130924151154_create_users.rb
      invoke    test_unit
 
      create      test/models/user_test.rb
     create    app/models/user.rb
      create      test/fixtures/users.yml
 
      invoke  resource_route
     invoke    test_unit
      route    resources :users
 
      invoke  scaffold_controller
     create      test/models/user_test.rb
      create    app/controllers/users_controller.rb
 
      invoke    erb
     create      test/fixtures/users.yml
      create      app/views/users
 
      create      app/views/users/index.html.erb
     invoke  resource_route
      create      app/views/users/edit.html.erb
 
      create      app/views/users/show.html.erb
      route   resources :users
      create      app/views/users/new.html.erb
 
      create      app/views/users/_form.html.erb
     invoke  scaffold_controller
      invoke    test_unit
 
      create      test/controllers/users_controller_test.rb
     create    app/controllers/users_controller.rb
      invoke    helper
 
      create      app/helpers/users_helper.rb
     invoke    erb
      invoke    jbuilder
 
      create      app/views/users/index.json.jbuilder
     create      app/views/users
      create      app/views/users/show.json.jbuilder
 
      invoke  test_unit
     create      app/views/users/index.html.erb
      create    test/application_system_test_case.rb
 
      create    test/system/users_test.rb
     create      app/views/users/edit.html.erb
      invoke  assets
 
      invoke    coffee
     create      app/views/users/show.html.erb
      create      app/assets/javascripts/users.coffee
 
      invoke    scss
     create      app/views/users/new.html.erb
      create      app/assets/stylesheets/users.scss
 
      invoke  scss
     create      app/views/users/_form.html.erb
      create    app/assets/stylesheets/scaffolds.scss
 
     invoke    test_unit
 
     create      test/controllers/users_controller_test.rb
 
     invoke    helper
 
     create      app/helpers/users_helper.rb
 
     invoke    jbuilder
 
     create      app/views/users/index.json.jbuilder
 
     create      app/views/users/show.json.jbuilder
 
     invoke  test_unit
 
     create    test/application_system_test_case.rb
 
     create    test/system/users_test.rb
 
     invoke  assets
 
     invoke    coffee
 
     create      app/assets/javascripts/users.coffee
 
     invoke    scss
 
     create      app/assets/stylesheets/users.scss
 
     invoke  scss
 
     create    app/assets/stylesheets/scaffolds.scss
</syntaxhighlight>
</syntaxhighlight>


بالنظر إلى هذا الناتج، من السهل فهم كيفية عمل المولدات في Rails 3.0 وما فوقها. مولد السقالة لا يولد أي شيء في الواقع، إنه يستدعي الآخرين فقط للقيام بالعمل. هذا يسمح لنا بإضافة / استبدال / إزالة أي من تلك الإستدعاءات. على سبيل المثال، يستدعي مولد السقالات مولد scaffold_controller، الذي يستدعي مولدات erb و test_unit و helper. نظرًا لأن كل مولد لديه مسؤولية واحدة، فإنه من السهل إعادة استخدامه، مع تجنب تكرار الرمز.
بالنظر إلى هذا الناتج، من السهل فهم كيفية عمل المولدات في الإصدار 3.0 وما بعد من ريلز. مولد السقالة scaffold لا يولد أي شيء في الواقع، إنه يستدعي الآخرين فقط للقيام بالعمل. هذا يسمح لنا بإضافة أو استبدال أو إزالة أي من تلك الإستدعاءات. على سبيل المثال، يستدعي المولد scaffold المولد scaffold_controller، الذي يستدعي المولدات erb و test_unit و helper. نظرًا لأن كل مولد لديه مسؤولية واحدة، فإنه من السهل إعادة استخدامه، مع تجنب تكرار الشيفرة.


إذا كنا نريد تجنب التوليد الافتراضي لملف app/assets/stylesheets/scaffolds.scss عند سقالة مورد جديد يمكننا تعطيل scaffold_stylesheet:
إذا كنا نريد تجنب التوليد الافتراضي للملف app/assets/stylesheets/scaffolds.scss عند توليد مورد جديد عبر المولد scaffold، يمكننا تعطيل <code>scaffold_stylesheet</code>:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
 
  g.scaffold_stylesheet false
 g.scaffold_stylesheet false
end
 
End
</syntaxhighlight>
</syntaxhighlight>


سيكون التخصيص التالي على سير العمل هو التوقف عن توليد ورقة الأنماط وجافا سكريبت وملفات اختبار التثبيت للسقالات بالكامل. نُحقق ذلك عن طريق تغيير إعدادات التكوين لدينا إلى ما يلي:
سيكون التخصيص التالي على سير العمل هو التوقف عن توليد [[CSS|ورقة الأنماط]] و<nowiki/>[[JavaScript|جافاسكريبت]] و<nowiki/>[[Rails/testing#.D8.AD.D9.82.D9.8A.D9.82.D8.A9 .D8.AA.D8.AD.D8.B6.D9.8A.D8.B1.D8.A7.D8.AA .D8.A7.D9.84.D8.A7.D8.AE.D8.AA.D8.A8.D8.A7.D8.B1 .28Fixtures.29|ملفات تحضيرات الاختبار]] للسقالات بالكامل. نُحقق ذلك عن طريق تغيير إعدادات الضبط لدينا إلى ما يلي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
 
  g.orm             :active_record
 g.orm             :active_record
  g.template_engine :erb
 
  g.test_framework :test_unit, fixture: false
 g.template_engine :erb
  g.stylesheets     false
 
  g.javascripts     false
 g.test_framework  :test_unit, fixture: false
end
 
 g.stylesheets     false
 
 g.javascripts     false
 
End
</syntaxhighlight>
</syntaxhighlight>


إذا قمنا بإنشاء مورد آخر بمولد السقالة، يمكننا ملاحظة أنه لن ينشئ أوراق الأنماط وجافا سكريبت وملفات التثبيت بعد الآن. إذا كنت ترغب في تخصيصها بشكل أكبر، على سبيل المثال لاستخدام DataMapper و RSpec بدلاً من Active Record و TestUnit، فإن الأمر يتعلق فقط بإضافة الجواهر الخاصة بهم إلى التطبيق الخاص بك وتكوين المولدات الخاصة بك.
إذا قمنا بإنشاء مورد آخر عبر المولد scaffold، يمكننا ملاحظة أنه لن ينشئ أوراق الأنماط وشيفرة جافاسكريبت وملفات تحضيرات الاختبار بعد الآن. إذا كنت ترغب في تخصيصها بشكل أكبر، على سبيل المثال لاستخدام DataMapper و RSpec بدلًا من [[Rails/active record|Active Record]] و TestUnit، فإن الأمر يتعلق فقط بإضافة الجواهر الخاصة بهم إلى التطبيق الخاص بك وضبط المولدات الخاصة بك.


لإثبات ذلك، سننشئ مولد مساعد جديد هذا ببساطة يضيف بعض نُسخ متغيرات القُراء.  أولاً، نُنشئ مولد داخل مساحة اسم rails، حيث أن هذا هو المكان الذي تبحث فيه rails عن المولدات المستخدمة كخطافات:
لإثبات ذلك، سننشئ مولدًا مساعدًا جديدًا يضيف ببساطة بعض متغيرات النسخة. أولًا، نُنشئ مولدًا داخل مجال الاسم <code>rails</code>، حيث أن هذا هو المكان الذي تبحث فيه ريلز عن المولدات المستخدمة كخطافات:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
$ bin/rails generate generator rails/my_helper
$ bin/rails generate generator rails/my_helper
      create  lib/generators/rails/my_helper
      create  lib/generators/rails/my_helper/my_helper_generator.rb
      create  lib/generators/rails/my_helper/USAGE
      create  lib/generators/rails/my_helper/templates
      invoke  test_unit
      create    test/lib/generators/rails/my_helper_generator_test.rb


     create  lib/generators/rails/my_helper
     create  lib/generators/rails/my_helper/my_helper_generator.rb
     create  lib/generators/rails/my_helper/USAGE
     create  lib/generators/rails/my_helper/templates
     invoke  test_unit
     create    test/lib/generators/rails/my_helper_generator_test.rb
</syntaxhighlight>
</syntaxhighlight>


بعد ذلك، يمكننا حذف كلٍّ من الدليل templates واستدعاء تابع الفئة class_root من المولد الجديد، لأننا لن نحتاج إليهم. أضف التابع أدناه، لذلك يبدو مولدنا كما يلي:
بعد ذلك، يمكننا حذف كلٍّ من المجلد templates وتابع الصنف <code>class_root</code> الذي يستدعى من المولد الجديد، لأننا لن نحتاج إليهما. أضف التابع أدناه، لذلك يبدو مولدنا كما يلي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<nowiki>#</nowiki> lib/generators/rails/my_helper/my_helper_generator.rb
# lib/generators/rails/my_helper/my_helper_generator.rb
 
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
 
  def create_helper_file
 def create_helper_file
    create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
 
   create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
 
module #{class_name}Helper
module #{class_name}Helper
 
  attr_reader :#{plural_name}, :#{plural_name.singularize}
 attr_reader :#{plural_name}, :#{plural_name.singularize}
 
end
end
 
    FILE
   FILE
  end
 
 end
 
end
end
</syntaxhighlight>
</syntaxhighlight>


يمكننا تجربة مولدنا الجديد عن طريق إنشاء مساعد للمنتجات:
يمكننا تجربة مولدنا الجديد عن طريق إنشاء مساعد للمنتجات:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate my_helper products
$ bin/rails generate my_helper products
 
      create  app/helpers/products_helper.rb
     create  app/helpers/products_helper.rb
</syntaxhighlight>
</syntaxhighlight>


سطر 333: سطر 244:
</syntaxhighlight>
</syntaxhighlight>


وهو ما كنا نتوقعه. يمكننا الآن أن نقول للسقالة ان تستخدم مولد المساعد الجديد الخاص بنا عن طريق تحرير config / application.rb مرة أخرى:
وهو ما كنا نتوقعه. يمكننا الآن أن نخبر المولد scaffold أن يستخدم المولد المساعد الجديد الخاص بنا عن طريق تعديل الملف config/application.rb مرة أخرى بالشكل التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
 
  g.orm             :active_record
 g.orm             :active_record
  g.template_engine :erb
 
  g.test_framework :test_unit, fixture: false
 g.template_engine :erb
  g.stylesheets     false
 
  g.javascripts     false
 g.test_framework  :test_unit, fixture: false
  g.helper         :my_helper
 
end
 g.stylesheets     false
 
 g.javascripts     false
 
 g.helper          :my_helper
 
End
</syntaxhighlight>
</syntaxhighlight>


ونرى ذلك في العمل عند استدعاء المولد:
ونرى ذلك في العمل عند استدعاء المولد:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
$ bin/rails generate scaffold Article body:text
$ bin/rails generate scaffold Article body:text
 
      [...]
     [...]
      invoke    my_helper
 
      create      app/helpers/articles_helper.rb
     invoke    my_helper
 
     create      app/helpers/articles_helper.rb
</syntaxhighlight>
</syntaxhighlight>


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


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


للقيام بذلك، يمكننا تغيير المولد بهذه الطريقة:
للقيام بذلك، يمكننا تغيير المولد بهذه الطريقة:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<nowiki>#</nowiki> lib/generators/rails/my_helper/my_helper_generator.rb
# lib/generators/rails/my_helper/my_helper_generator.rb
 
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
 
  def create_helper_file
 def create_helper_file
    create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
 
   create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
 
module #{class_name}Helper
module #{class_name}Helper
 
  attr_reader :#{plural_name}, :#{plural_name.singularize}
 attr_reader :#{plural_name}, :#{plural_name.singularize}
end
 
    FILE
  end
  hook_for :test_framework
end
end
   FILE
 end
 hook_for :test_framework
End
</syntaxhighlight>
</syntaxhighlight>


الآن، عندما يُستدعى المولد المساعد وتُكون TestUnit كإطار اختبار، سيحاول استدعاء كلا Rails :: TestUnitGenerator و TestUnit :: MyHelperGenerator. نظرًا لأنه لم يُعرف أيٍّ منها، يمكننا أن نطلب من المولد الخاص بنا استدعاء TestUnit :: Generators :: HelperGenerator بدلاً من ذلك، والذي يُعرف لأنه منشئ Rails. للقيام بذلك، نحن بحاجة فقط إلى إضافة:
الآن، عندما يُستدعَى المولد المساعد وتُكون TestUnit كإطار اختبار، سيحاول استدعاء <code>Rails::TestUnitGenerator</code> و <code>TestUnit::MyHelperGenerator</code> كلاهما. نظرًا لأنه لم يُعرَّف أي منها، يمكننا أن نطلب من المولد الخاص بنا استدعاء <code>TestUnit::Generators::HelperGenerator</code> بدلًا من ذلك، إذ هو مُعرَّف لأنه مولد ريلز. للقيام بذلك، نحن بحاجة فقط إلى إضافة:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<nowiki>#</nowiki> Search for :helper instead of :my_helper
# :my_helper بدلًا من :helper ابحث عن
 
hook_for :test_framework, as: :helper
hook_for :test_framework, as: :helper
</syntaxhighlight>
</syntaxhighlight>


والآن يمكنك إعادة تشغيل السقالة لمورد آخر ورؤيتها تولد اختبارات أيضًا!
والآن يمكنك إعادة تشغيل المولد scaffold لمورد آخر للتأكد من توليده للاختبارات أيضًا!


== تخصيص سير العمل الخاص بك عن طريق تغيير قوالب المولدات ==
== تخصيص سير العمل الخاص بك عن طريق تغيير قوالب المولدات ==
في الخطوة أعلاه، أردنا ببساطة إضافة سطر إلى المساعد الذي اُنشأ، دون إضافة أي وظائف إضافية. هناك طريقة أبسط للقيام بذلك، ومن خلال استبدال قوالب المولدات الموجودة بالفعل، في تلك الحالة Rails :: Generators :: HelperGenerator.
في الخطوة أعلاه، أردنا ببساطة إضافة سطر إلى المساعد الذي اُنشأ، دون إضافة أي وظائف إضافية. هناك طريقة أبسط للقيام بذلك، ومن خلال استبدال قوالب المولدات الموجودة بالفعل، في تلك الحالة <code>Rails::Generators::HelperGenerator</code>.


في Rails 3.0 وأعلى، لا تبحث المولدات فقط في المصدر الاصل عن القوالب، بل تبحث أيضًا عن القوالب في مسارات أخرى. واحد منهم هو lib / templates. بما أننا نريد تخصيص Rails :: Generators :: HelperGenerator، يمكننا القيام بذلك ببساطة عن طريق إنشاء نسخة القالب داخل lib / templates / rails / helper بالاسم helper.rb. لذلك دعونا إنشاء هذا الملف مع المحتوى التالي:
في الإصدار 3.0 وما بعده من ريلز، لا تبحث المولدات فقط في المصدر الأصل عن القوالب، بل تبحث أيضًا عن القوالب في مسارات أخرى. واحد منهم هو lib/templates. بما أننا نريد تخصيص <code>Rails::Generators::HelperGenerator</code>، يمكننا القيام بذلك ببساطة عن طريق إنشاء نسخة القالب داخل lib/templates/rails/helper بالاسم helper.rb. لذلك دعنا ننشئ هذا الملف مع المحتوى التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
module <%= class_name %>Helper
module <%= class_name %>Helper
 
  attr_reader :<%= plural_name %>, :<%= plural_name.singularize %>
 attr_reader :<%= plural_name %>, :<%= plural_name.singularize %>
end
 
End
</syntaxhighlight>
</syntaxhighlight>


وتغيير آخر تغيير في config / application.rb:
والرجوع إلى آخر تغيير في config/application.rb:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
 
  g.orm             :active_record
 g.orm             :active_record
  g.template_engine :erb
 
  g.test_framework :test_unit, fixture: false
 g.template_engine :erb
  g.stylesheets     false
 
  g.javascripts     false
 g.test_framework  :test_unit, fixture: false
 
 g.stylesheets     false
 
 g.javascripts     false
 
end
end
</syntaxhighlight>
</syntaxhighlight>


إذا قمت بإنشاء مورد آخر، يمكنك أن ترى أننا نحصل على نفس النتيجة بالضبط! وهذا مفيد إذا كنت تريد تخصيص قوالب سقالة و / أو تخطيطك من خلال إنشاء edit.html.erb و index.html.erb وما إلى ذلك داخل lib / templates / erb / scaffold.
إذا قمت بإنشاء مورد آخر، يمكنك أن ترى أننا نحصل على نفس النتيجة بالضبط! وهذا مفيد إذا كنت تريد تخصيص قوالب المولد scaffold و/أو تخطيطك من خلال إنشاء edit.html.erb و index.html.erb وما إلى ذلك داخل lib/templates/erb/scaffold.


تستخدم قوالب سقالة في Rails علامات ERB بشكل متكرر؛ هذه العلامات تحتاج إلى أن تُخلص بحيث يكون الناتج الذي أنشأه رمز ERB صالحًا.
تستخدم قوالب المولد scaffold في ريلز وسوم ERB بشكل متكرر؛ هذه الوسوم تحتاج إلى أن تُهرَّب بحيث يكون الناتج الذي أنشأه وسم ERB صالح.


على سبيل المثال، ستكون علامة ERB الآجلة التالية مطلوبة في القالب (لاحظ النسبة الزائدة٪)
على سبيل المثال، سيكون الوسم ERB المهرَّب التالي مطلوبًا في القالب (لاحظ الإشارة % الزائدة) ...
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<%%= stylesheet_include_tag :application %>
<%%= stylesheet_include_tag :application %>
</syntaxhighlight>
</syntaxhighlight>


... لتوليد الإخراج التالي:
... لتوليد الناتج التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
<%= stylesheet_include_tag :application %>
<%= stylesheet_include_tag :application %>
</syntaxhighlight>
</syntaxhighlight>


== إضافة المولدات الاحتياطية ==
== إضافة تراجعات للمولدات ==
ميزة واحدة أخيرة حول المولدات التي هي مفيدة جدا لمولدات المكوّنات الإضافيّة. على سبيل المثال، تخيل أنك تريد إضافة ميزة أعلى TestUnit مثل shoulda. بما أن TestUnit ينفذ بالفعل جميع المولدات المطلوبة من قبل Rails و shoulda يريد فقط استبدال جزء منه، فلا توجد حاجة إلى إعادة تشغيل بعض المولدات مرة أخرى، يمكن ببساطة أن تخبر Rails لاستخدام مولد TestUnit إذا لم يعثر على أي منها تحت مساحة اسم Shoulda.
ميزة واحدة أخيرة حول المولدات التي هي مفيدة جدًا لمولدات المكوّنات الإضافيّة. على سبيل المثال، تخيل أنك تريد إضافة ميزة أعلى TestUnit مثل [https://github.com/thoughtbot/shoulda shoulda]. بما أن TestUnit ينفذ بالفعل جميع المولدات المطلوبة من قبل ريلز و shoulda يريد فقط استبدال جزء منه، فلا توجد حاجة إلى إعادة تشغيل بعض المولدات مرة أخرى، يمكن ببساطة أن تخبر ريلز باستخدام مولد TestUnit إذا لم يعثر على أي منها تحت مجال الاسم Shoulda.


يمكننا بسهولة محاكاة هذا السلوك عن طريق تغيير config / application.rb الخاص بنا مرة أخرى:
يمكننا بسهولة محاكاة هذا السلوك عن طريق تغيير config/application.rb الخاص بنا مرة أخرى:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
config.generators do |g|
config.generators do |g|
  g.orm            :active_record
  g.template_engine :erb
  g.test_framework  :shoulda, fixture: false
  g.stylesheets    false
  g.javascripts    false
  # إضافة تراجع
  g.fallbacks[:shoulda] = :test_unit
end
</syntaxhighlight>


 g.orm             :active_record
الآن، إذا أنشئت <code>Comment</code> عبر المولد scaffold، سترى أنه تُستدعَى المولدات shoulda، ثم يرجع إلى المولدات TestUnit في النهاية:
 
<syntaxhighlight lang="shell">
 g.template_engine :erb
 
 g.test_framework  :shoulda, fixture: false
 
 g.stylesheets     false
 
 g.javascripts     false
 
 # Add a fallback!
 
 g.fallbacks[:shoulda] = :test_unit
 
End
</syntaxhighlight>


الآن، إذا أنشئت سقالة تعليق، سترى أنه يُستدعى مولدات shoulda، وفي النهاية، يرجع إلى مولدات TestUnit:
<syntaxhighlight lang="rails">
$ bin/rails generate scaffold Comment body:text
$ bin/rails generate scaffold Comment body:text
      invoke  active_record
      create    db/migrate/20130924143118_create_comments.rb
      create    app/models/comment.rb
      invoke    shoulda
      create      test/models/comment_test.rb
      create      test/fixtures/comments.yml
      invoke  resource_route
      route    resources :comments
      invoke  scaffold_controller
      create    app/controllers/comments_controller.rb
      invoke    erb
      create      app/views/comments
      create      app/views/comments/index.html.erb
      create      app/views/comments/edit.html.erb
      create      app/views/comments/show.html.erb
      create      app/views/comments/new.html.erb
      create      app/views/comments/_form.html.erb
      invoke    shoulda
      create      test/controllers/comments_controller_test.rb
      invoke    my_helper
      create      app/helpers/comments_helper.rb
      invoke    jbuilder
      create      app/views/comments/index.json.jbuilder
      create      app/views/comments/show.json.jbuilder
      invoke  test_unit
      create    test/application_system_test_case.rb
      create    test/system/comments_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/comments.coffee
      invoke    scss


     invoke  active_record
     create    db/migrate/20130924143118_create_comments.rb
     create    app/models/comment.rb
     invoke    shoulda
     create      test/models/comment_test.rb
     create      test/fixtures/comments.yml
     invoke  resource_route
      route   resources :comments
     invoke  scaffold_controller
     create    app/controllers/comments_controller.rb
     invoke    erb
     create      app/views/comments
     create      app/views/comments/index.html.erb
     create      app/views/comments/edit.html.erb
     create      app/views/comments/show.html.erb
     create      app/views/comments/new.html.erb
     create      app/views/comments/_form.html.erb
     invoke    shoulda
     create      test/controllers/comments_controller_test.rb
     invoke    my_helper
     create      app/helpers/comments_helper.rb
     invoke    jbuilder
     create      app/views/comments/index.json.jbuilder
     create      app/views/comments/show.json.jbuilder
     invoke  test_unit
     create    test/application_system_test_case.rb
     create    test/system/comments_test.rb
     invoke  assets
     invoke    coffee
     create      app/assets/javascripts/comments.coffee
     invoke    scss
</syntaxhighlight>
</syntaxhighlight>


تسمح المراجعات للمولدات الخاصة بك بتحمل مسؤولية واحدة، مما يزيد من إعادة استخدام الاكواد ويقلل من مقدار التكرار.
تسمح التراجعات للمولدات الخاصة بك بتحمل مسؤولية واحدة، مما يزيد من إعادة استخدام الشيفرات ويقلل من مقدار التكرار.


== قوالب التطبيق ==
== قوالب التطبيق ==
الآن بعد أن رأيت كيف يمكن استخدام المولدات داخل أحد التطبيقات، هل تعلم أيضًا أنه يمكن استخدامها أيضًا لإنشاء التطبيقات؟ يشار إلى هذا النوع من المولد باسم "قالب". هذه نظرة عامة موجزة عن API Templates. للحصول على الوثائق التفصيلية، انظر دليل قوالب تطبيقات Rails.
الآن بعد أن رأيت كيف يمكن استخدام المولدات داخل أحد التطبيقات، هل تعلم أيضًا أنه يمكن استخدامها أيضًا لإنشاء التطبيقات؟ يشار إلى هذا النوع من المولد باسم "قالب" (template). هذه نظرة عامة موجزة عن الواجهة Templates البرمجية. للحصول على التوثيق التفصيلي، انظر دليل [[Rails/rails application templates|قوالب تطبيقات ريلز]].
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
gem "rspec-rails", group: "test"
gem "rspec-rails", group: "test"
gem "cucumber-rails", group: "test"
gem "cucumber-rails", group: "test"
 
if yes?("Would you like to install Devise?")
if yes?("Would you like to install Devise?")
 
  gem "devise"
 gem "devise"
  generate "devise:install"
 
  model_name = ask("What would you like the user model to be called? [user]")
 generate "devise:install"
  model_name = "user" if model_name.blank?
 
  generate "devise", model_name
 model_name = ask("What would you like the user model to be called? [user]")
end
 
 model_name = "user" if model_name.blank?
 
 generate "devise", model_name
 
End
</syntaxhighlight>
</syntaxhighlight>


في النموذج أعلاه، نحدد أن التطبيق يعتمد على rspec-rails و جوهرة cucumber-rails لذلك يُضافان إلى مجموعة test في Gemfile.
في النموذج أعلاه، نحدد أن التطبيق يعتمد على الجوهرة rspec-rails والجوهرة cucumber-rails لذلك يُضافان إلى المجموعة test في الملف Gemfile.
 
ثم نطرح سؤالًا على المستخدم حول ما إذا كان يرغب في تثبيت Devise أم لا. إذا رد المستخدم "y" أو "yes" على هذا السؤال، سيضيف القالب Devise إلى Gemfile خارج أي مجموعة، ثم يُشغل المولد devise: install.


ثم يأخذ هذا القالب مدخلات المستخدمين ويُشغل مولد devise، مع إجابة المستخدم من السؤال الأخير الذي مُرر إلى هذا المولد.
ثم نطرح سؤالًا على المستخدم حول ما إذا كان يرغب في تثبيت Devise أم لا. إذا رد المستخدم "y" أو "yes" على هذا السؤال، سيضيف القالب Devise إلى الملف Gemfile خارج أي مجموعة، ثم يُشغل المولد <code>devise: install</code>.


تخيل أن هذا القالب كان في ملف يسمى template.rb. يمكننا استخدامه لتعديل نتائج الأمر rails new باستخدام الخيار -m وتمريره في اسم الملف:
ثم يأخذ هذا القالب مدخلات المستخدمين ويُشغل المولد devise، مع إجابة المستخدم من السؤال الأخير الذي مُرر إلى هذا المولد.


تخيل أن هذا القالب كان في ملف يسمى template.rb. يمكننا استخدامه لتعديل نتائج الأمر <code>rails new</code> باستخدام الخيار ‎<code>-m</code> وتمريره في اسم الملف:<syntaxhighlight lang="shell">
$ rails new thud -m template.rb
$ rails new thud -m template.rb
</syntaxhighlight>سيولد هذا الأمر التطبيق Thud، ثم يطبق القالب إلى الناتج المولد.


سينشئ هذا الأمر تطبيق Thud، ثم تطبيق القالب الى الناتج الذي أُنشأ.
لا يجب تخزين القوالب على النظام المحلي، كما يدعم الخيار ‎<code>-m</code> أيضًا النماذج عبر الإنترنت:
 
<syntaxhighlight lang="shell">
لا يجب تخزين القوالب على النظام المحلي، كما يدعم الخيار -m أيضًا النماذج عبر الإنترنت:
$ rails new thud -m https://gist.github.com/radar/722911/raw/
<syntaxhighlight lang="rails">
$ rails new thud -m <nowiki>https://gist.github.com/radar/722911/raw/</nowiki>
</syntaxhighlight>
</syntaxhighlight>


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


== إضافة وسيطات سطر الأوامر ==
== إضافة وسائط سطر الأوامر ==
يمكن تعديل مولدات Rails بسهولة لقبول وسائط سطر الأوامر المخصصة. هذه الوظيفة تأتي من Thor:
يمكن تعديل مولدات ريلز بسهولة لقبول وسائط سطر الأوامر المخصصة. هذه الوظيفة تأتي من Thor:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
class_option :scope, type: :string, default: 'read_products'
class_option :scope, type: :string, default: 'read_products'
سطر 585: سطر 423:


الآن يمكن استدعاء المولد الخاص بنا على النحو التالي:
الآن يمكن استدعاء المولد الخاص بنا على النحو التالي:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="shell">
rails generate initializer --scope write_products
rails generate initializer --scope write_products
</syntaxhighlight>
</syntaxhighlight>


يمكن الوصول إلى وسائط سطر الأوامر من خلال التابع options داخل فئة المولد. منها مثلا:
يمكن الوصول إلى وسائط سطر الأوامر من خلال التابع <code>options</code> داخل صنف المولد مثل:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
@scope = options['scope']
@scope = options['scope']
سطر 595: سطر 433:


== توابع المولد ==
== توابع المولد ==
فيما يلي التوابع المتوفرة لكل من المولدات والقوالب الخاصة بـ Rails.
فيما يلي التوابع المتوفرة لكل من المولدات والقوالب الخاصة بريلز.


لا يُغطي هذا الدليل التوابع التي يقدمها Thor ويمكن العثور عليها في وثائق Thor.
'''ملاحظة''': لا يُغطي هذا الدليل التوابع التي يقدمها Thor ويمكن العثور عليها في [http://rdoc.info/github/erikhuda/thor/master/Thor/Actions.html توثيق Thor].


=== الجوهرة ===
=== <code>gem</code> ===
يحدد تبعية الجوهرة للتطبيق.
يحدد تبعية الجوهرة للتطبيق.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
gem "rspec", group: "test", version: "2.1.0"
gem "rspec", group: "test", version: "2.1.0"
gem "devise", "1.1.5"
gem "devise", "1.1.5"
</syntaxhighlight>
</syntaxhighlight>


الخيارات المتاحة هي:
الخيارات المتاحة هي:
* group: - المجموعة في Gemfile حيث يجب أن تذهب هذه الجوهرة.
* <code>group:‎</code> - المجموعة في الملف Gemfile حيث يجب أن تذهب هذه الجوهرة.
* Version: - سلسلة إصدار الجوهرة التي تريد استخدامها. يمكن أيضًا تحديده كوسيطة ثانية للتابع.
* <code>version:‎</code> - سلسلة إصدار الجوهرة التي تريد استخدامها. يمكن أيضًا تحديده كوسيطٍ ثانٍ للتابع.
* Git: - عنوان URL لمستودع git لهذه الجوهرة.
* <code>git:‎</code> - عنوان URL لمستودع git لهذه الجوهرة.
تُوضع أي خيارات إضافية مُررت إلى هذا التابع في نهاية السطر:
تُوضع أي خيارات إضافية مُررت إلى هذا التابع في نهاية السطر:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
gem "devise", git: "<nowiki>https://github.com/plataformatec/devise.git</nowiki>", branch: "master"
gem "devise", git: "https://github.com/plataformatec/devise.git", branch: "master"
</syntaxhighlight>
</syntaxhighlight>


سيضع الكود السابق السطر التالي في Gemfile:
ستضع الشيفرة السابقة السطر التالي في الملف Gemfile:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
gem "devise", git: "<nowiki>https://github.com/plataformatec/devise.git</nowiki>", branch: "master"
gem "devise", git: "https://github.com/plataformatec/devise.git", branch: "master"
</syntaxhighlight>
</syntaxhighlight>


=== Gem_group ===
=== <code>gem_group</code> ===
تلتف مدخلات الجوهرة داخل المجموعة:
يغلف مدخلات الجوهرة داخل المجموعة:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
gem_group :development, :test do
gem_group :development, :test do
 
  gem "rspec-rails"
 gem "rspec-rails"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Add_source ===
=== <code>add_source</code> ===
يضيف مصدر محدد إلى Gemfile:
يضيف مصدرًا محددًا إلى الملف Gemfile:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
add_source "<nowiki>http://gems.github.com</nowiki>"
add_source "http://gems.github.com"
 
</syntaxhighlight>
</syntaxhighlight>


هذا التابع يأخذ أيضا كتلة:
هذا التابع يأخذ أيضا كتلة:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
add_source "<nowiki>http://gems.github.com</nowiki>" do
add_source "http://gems.github.com" do
 
  gem "rspec-rails"
 gem "rspec-rails"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Inject_into_file ===
=== <code>inject_into_file</code> ===
حقن كتلة من التعليمات البرمجية في موضع محدد في ملفك.
يحقن كتلة من التعليمات البرمجية في موضع محدد في ملفك.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
inject_into_file 'name_of_file.rb', after: "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
inject_into_file 'name_of_file.rb', after: "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
 
  puts "Hello World"
 puts "Hello World"
 
RUBY
RUBY
 
end
End
</syntaxhighlight>
 
===<code>gsub_file</code>===
=== Gsub_file ===
يستبدل نصًّا داخل الملف.<syntaxhighlight lang="rails">
يستبدل النص داخل الملف.
<syntaxhighlight lang="rails">
gsub_file 'name_of_file.rb', 'method.to_be_replaced', 'method.the_replacing_code'
gsub_file 'name_of_file.rb', 'method.to_be_replaced', 'method.the_replacing_code'
</syntaxhighlight>
</syntaxhighlight>يمكن استخدام [[Ruby/Regexp|التعبيرات النمطية]] لجعل هذا التابع أكثر دقة. يمكنك أيضًا استخدام <code>append_file</code> و <code>prepend_file</code> بالطريقة نفسها لوضع الشفرة في بداية ونهاية الملف على التوالي.
 
يمكن استخدام التعبيرات العادية لجعل هذا التابع أكثر دقة. يمكنك أيضًا استخدام append_file و prepend_file بالطريقة نفسها لوضع الشفرة في بداية ونهاية الملف على التوالي.


=== Application ===
=== <code>application</code> ===
يضيف سطر إلى config / application.rb مباشرةً بعد تعريف فئة التطبيق.
يضيف سطرًا إلى config/application.rb مباشرةً بعد تعريف صنف التطبيق.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
application "config.asset_host = '<nowiki>http://example.com'</nowiki>"
application "config.asset_host = 'http://example.com'"
</syntaxhighlight>
</syntaxhighlight>


سطر 674: سطر 502:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
application do
application do
 
  "config.asset_host = 'http://example.com'"
 "config.asset_host = '<nowiki>http://example.com'</nowiki>"
 
end
end
</syntaxhighlight>
</syntaxhighlight>


الخيارات المتاحة هي:
الخيارات المتاحة هي:
* Env: - حدد بيئة لخيار التوصيف هذا. إذا كنت ترغب في استخدام هذا الخيار مع بناء جملة الكتلة، يكون بناء الجملة الموصى به كما يلي:
* <code>env:‎</code> - حدد بيئة لخيار التوصيف هذا. إذا كنت ترغب في استخدام هذا الخيار مع صياغة الكتلة، تكون الصياغة الموصى بها كما يلي:
<syntaxhighlight lang="rails">
application(nil, env: "development") do
application(nil, env: "development") do
<syntaxhighlight lang="rails">
  "config.asset_host = 'http://localhost:3000'"
 "config.asset_host = '<nowiki>http://localhost:3000'</nowiki>"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Git ===
=== <code>git</code> ===
لتشغيل الأمر git المحدد:
يشغل الأمر <code>git</code> المحدد:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
git :init
git :init
git add: "."
git add: "."
git commit: "-m First commit!"
git commit: "-m First commit!"
git add: "onefile.rb", rm: "badfile.cxx"
git add: "onefile.rb", rm: "badfile.cxx"
</syntaxhighlight>
</syntaxhighlight>


تكون قيم التجزئة هنا هي الوسيطات أو الخيارات التي مُررت إلى أمر git المحدد. وفقًا للمثال النهائي الموضح هنا، يمكن تحديد عدة أوامر git في وقت واحد، ولكن لا يُضمن ترتيب تشغيلها بنفس الترتيب المحدد.
تكون قيم [[Ruby/Hash|الجدول Hash]] هنا هي الوسائط أو الخيارات التي مُررت إلى الأمر <code>git</code> المحدد. وفقًا للمثال النهائي الموضح هنا، يمكن تحديد عدة أوامر <code>git</code> في وقت واحد، ولكن لا يُضمن ترتيب تشغيلها بنفس الترتيب المحدد.


=== Vendor ===
=== <code>vendor</code> ===
يضع ملفًا في vendor يحتوي على الشفرة المحددة.
يضع ملفًا في vendor الذي يحتوي على الشيفرة المحددة.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
vendor "sekrit.rb", '#top secret stuff'
vendor "sekrit.rb", '#top secret stuff'
سطر 712: سطر 534:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
vendor "seeds.rb" do
vendor "seeds.rb" do
 
  "puts 'in your app, seeding your database'"
 "puts 'in your app, seeding your database'"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Lib ===
=== <code>lib</code> ===
يضع ملفًا في lib يحتوي على الشفرة المحددة.
يضع ملفًا في lib يحتوي على الشيفرة المحددة.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
lib "special.rb", "p Rails.root"
lib "special.rb", "p Rails.root"
سطر 727: سطر 547:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
lib "super_special.rb" do
lib "super_special.rb" do
 
  "puts 'Super special!'"
 "puts 'Super special!'"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Rakefile ===
=== <code>rakefile</code> ===
ينشئ ملف Rake في دليل lib / tasks الخاص بالتطبيق.
ينشئ ملف Rake في دليل lib/tasks الخاص بالتطبيق.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
rakefile "test.rake", 'task(:hello) { puts "Hello, there" }'
rakefile "test.rake", 'task(:hello) { puts "Hello, there" }'
سطر 742: سطر 560:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
rakefile "test.rake" do
rakefile "test.rake" do
 
  %Q{
 %Q{
    task rock: :environment do
 
      puts "Rockin'"
   task rock: :environment do
    end
 
  }
     puts "Rockin'"
 
   end
 
 }
 
end
end
</syntaxhighlight>
</syntaxhighlight>


=== Initializer ===
=== <code>initializer</code> ===
إنشاء مُهيئ في دليل config/initializers للتطبيق:
ينشئ مُهيئ في المجلد config/initializers للتطبيق:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
initializer "begin.rb", "puts 'this is the beginning'"
initializer "begin.rb", "puts 'this is the beginning'"
</syntaxhighlight>
</syntaxhighlight>


يأخذ هذا التابع أيضًا كتلة، متوقعًا إرجاع سلسلة:
يأخذ هذا التابع أيضًا كتلة، ويتوقع أن يعيد سلسلة نصية:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
initializer "begin.rb" do
initializer "begin.rb" do
 
  "puts 'this is the beginning'"
 "puts 'this is the beginning'"
end
 
End
</syntaxhighlight>
</syntaxhighlight>


=== Generate ===
=== <code>generate</code> ===
تشغيل المولد المحدد حيث تكون الوسيطة الأولى هي اسم المولد وتمرر الوسيطات المتبقية مباشرة إلى المولد.
يشغِّل المولد المحدد حيث يكون الوسيط الأولى هو اسم المولد وتمرر الوسائط المتبقية مباشرة إلى المولد.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
generate "scaffold", "forums title:string description:text"
generate "scaffold", "forums title:string description:text"
</syntaxhighlight>
</syntaxhighlight>


=== Rake ===
=== <code>rake</code> ===
لتشغيل مهمة Rake المحددة.
يشغل مهمة Rake محددة.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
rake "db:migrate"
rake "db:migrate"
سطر 784: سطر 594:


الخيارات المتاحة هي:
الخيارات المتاحة هي:
* env :  -  يحدد البيئة التي تشغل مهمة rake.
* <code>env:</code>‎  -  يحدد البيئة التي ستشغل مهمة rake.
* sudo: - أم لا لتشغيل هذه المهمة باستخدام sudo. الافتراضي false.
* <code>sudo:‎</code> - يحدد تشغيل هذه المهمة باستخدام sudo أم لا. القيمة الافتراضية هي: <code>false</code>.


=== Route ===
=== <code>route</code> ===
يضيف نصًا إلى ملف config / routes.rb:
يضيف نصًا إلى الملف config/routes.rb:
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
route "resources :people"
route "resources :people"
</syntaxhighlight>
</syntaxhighlight>


=== Readme ===
=== <code>readme</code> ===
إخراج محتويات الملف في source_path للقالب، عادة ما يكون README.
يطبع محتويات الملف في <code>source_path</code> للقالب، عادة ما يكون README.
<syntaxhighlight lang="rails">
<syntaxhighlight lang="rails">
readme "README"
readme "README"

المراجعة الحالية بتاريخ 08:59، 25 مارس 2019

مولدات ريلز هي أداة أساسية إذا كنت تخطط لتحسين سير عملك. مع هذا الدليل سوف تتعلم كيفية إنشاء المولدات وتخصيص المولدات الموجودة.

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

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

الاتصال الأول

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

$ rails new myapp
$ cd myapp
$ bin/rails generate

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

$ bin/rails generate helper --help

إنشاء المولد الأول الخاص بك

منذ الإصدار 3.0 من ريلز، تنشأ المولدات أعلى Thor. يوفر Thor خيارات قوية للتحليل، وواجهة برمجة تطبيقات رائعة لمعالجة الملفات. على سبيل المثال، لإنشاء مولد ينشئ ملف مُهيئ يسمى initializer.rb داخل config/initializers.

الخطوة الأولى هي إنشاء ملف في lib/generators/initializer_generator.rb بالمحتوى التالي:

class InitializerGenerator < Rails::Generators::Base
  def create_initializer_file
    create_file "config/initializers/initializer.rb", "# Add initialization content here"
  end
end

ملاحظة: create_file هو تابع مقدم من Thor::Actions. يمكن العثور على توثيق للتابع create_file وتوابع Thor الأخرى في توثيق Thor.

مولدنا الجديد بسيط للغاية: فهو يرث من Rails::Generators::Base وله تعريف واحد للتابع. عندما يُستدعَى المولد، يُنفذ كل تابع عام في المولد بالترتيب التسلسلي الذي عُرِّف به. وأخيرًا، نستدعي التابع create_file الذي سينشئ ملفًا في الوجهة المحددة بالمحتوى المحدد. إذا كنت معتادًا على  قوالب الواجهة البرمجية (API) لتطبيق ريلز، فستشعر بشيء من الألفة عند استخدام واجهة برمجة التطبيقات للمولدات الجديدة.

لاستدعاء المولد الجديد، نحتاج فقط إلى القيام بما يلي:

$ bin/rails generate initializer

قبل أن نبدأ، لنرى وصف علامة المولد الجديد:

$ bin/rails generate initializer --help

ريلز عادةً ما تكون قادرة على توليد أوصاف جيدة إذا كان المولّد هو مجال اسم، مثل

ActiveRecord::Generators::ModelGenerator، ولكن ليس في هذه الحالة بالذات. يمكننا حل هذه المشكلة بطريقتين. الحل الأول هو استدعاء desc داخل مولدنا:

class InitializerGenerator < Rails::Generators::Base
  desc "This generator creates an initializer file at config/initializers"
  def create_initializer_file
    create_file "config/initializers/initializer.rb", "# Add initialization content here"
  end
end

الآن يمكننا رؤية الوصف الجديد من خلال استدعاء ‎--help على المولد الجديد. الطريقة الثانية لإضافة وصف هي عن طريق إنشاء ملف يسمى USAGE في نفس المجلد الموجود فيه مولدنا. سنقوم بذلك في الخطوة التالية.

إنشاء مولدات مع المولدات

المولدات نفسها لديها مولد:

$ bin/rails generate generator initializer
      create  lib/generators/initializer
      create  lib/generators/initializer/initializer_generator.rb
      create  lib/generators/initializer/USAGE
      create  lib/generators/initializer/templates
      invoke  test_unit
      create    test/lib/generators/initializer_generator_test.rb

هذا هو المولد الذي أُنشأ للتو:

class InitializerGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('templates', __dir__)
end

أولًا، لاحظ أننا نرث من Rails::Generators::NamedBase بدلًا من Rails::Generators::Base. هذا يعني أن مولدنا يتوقع وسيطًا واحدًا على الأقل، والذي سيكون اسم المُهيئ، وسيكون متاحًا في الشيفرة الخاص بنا في المتغير name.

يمكننا أن نرى ذلك من خلال استدعاء وصف هذا المولد الجديد (لا تنس حذف ملف المولد القديم):

$ bin/rails generate initializer --help
Usage:
  rails generate initializer NAME [options]

يمكننا أيضًا رؤية أن المولد الجديد لديه تابع صنف يُسمى source_root. يشير هذا التابع إلى مكان وضع قوالب المولد الخاصة بنا، إن وجدت، وبشكل افتراضي يشير إلى المجلد lib/generators/initializer/templates الذي أُُنشِئ.

لفهم معنى قالب المولد، نُنشئ الملف lib/generators/initializer/templates/initializer.rb بالمحتوى التالي:

# Add initialization content here

والآن دعنا نغير المولد لنسخ هذا القالب عند الاستدعاء:

class InitializerGenerator < Rails::Generators::NamedBase
  source_root File.expand_path('templates', __dir__)
 
  def copy_initializer_file
    copy_file "initializer.rb", "config/initializers/#{file_name}.rb"
  end
end

دعنا ننفذه على المولد الخاص بنا:

$ bin/rails generate initializer core_extensions

يمكننا أن نرى أنه أُنشئ مُهيئ باسم core_extensions في config/initializers/core_extensions.rb بمحتويات القالب الخاص بنا. وهذا يعني أن copy_file نسخ الملف في المصدر الأصل الخاص بنا إلى مسار الوجهة الذي قدمناه. يُنشَأ التابع file_name تلقائيًا عندما نرث من Rails::Generators::NamedBase.

سنشير إلى التوابع المتوفرة للمولدات في القسم الأخير من هذا الدليل.

البحث عن مولدات

عند تشغيل rails generate initializer core_extensions تتطلب ريلز هذه الملفات بدورها حتى تعثر على أحدها:

rails/generators/initializer/initializer_generator.rb
generators/initializer/initializer_generator.rb
rails/generators/initializer_generator.rb
generators/initializer_generator.rb

إذا لم يعثر على أي شيء، فستُعرَض رسالة خطأ.

ملاحظة: تضع الأمثلة أعلاه الملفات تحت تطبيق lib لأن المجلد المذكور ينتمي إلى ‎$LOAD_PATH.

تخصيص سير العمل الخاص بك

المولدات الخاصة بريلز مرنة بما يكفي لتسمح لك بتخصيص السقالات (scaffolding). يمكن ضبطها في config/application.rb، هذه بعض الافتراضات:

config.generators do |g|
  g.orm             :active_record
  g.template_engine :erb
  g.test_framework  :test_unit, fixture: true
end

قبل تخصيص سير العمل الخاص بنا، لنرى أولًا الشكل الذي تبدو عليه سقالاتنا (scaffold):

$ bin/rails generate scaffold User name:string
      invoke  active_record
      create    db/migrate/20130924151154_create_users.rb
      create    app/models/user.rb
      invoke    test_unit
      create      test/models/user_test.rb
      create      test/fixtures/users.yml
      invoke  resource_route
       route    resources :users
      invoke  scaffold_controller
      create    app/controllers/users_controller.rb
      invoke    erb
      create      app/views/users
      create      app/views/users/index.html.erb
      create      app/views/users/edit.html.erb
      create      app/views/users/show.html.erb
      create      app/views/users/new.html.erb
      create      app/views/users/_form.html.erb
      invoke    test_unit
      create      test/controllers/users_controller_test.rb
      invoke    helper
      create      app/helpers/users_helper.rb
      invoke    jbuilder
      create      app/views/users/index.json.jbuilder
      create      app/views/users/show.json.jbuilder
      invoke  test_unit
      create    test/application_system_test_case.rb
      create    test/system/users_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/users.coffee
      invoke    scss
      create      app/assets/stylesheets/users.scss
      invoke  scss
      create    app/assets/stylesheets/scaffolds.scss

بالنظر إلى هذا الناتج، من السهل فهم كيفية عمل المولدات في الإصدار 3.0 وما بعد من ريلز. مولد السقالة scaffold لا يولد أي شيء في الواقع، إنه يستدعي الآخرين فقط للقيام بالعمل. هذا يسمح لنا بإضافة أو استبدال أو إزالة أي من تلك الإستدعاءات. على سبيل المثال، يستدعي المولد scaffold المولد scaffold_controller، الذي يستدعي المولدات erb و test_unit و helper. نظرًا لأن كل مولد لديه مسؤولية واحدة، فإنه من السهل إعادة استخدامه، مع تجنب تكرار الشيفرة.

إذا كنا نريد تجنب التوليد الافتراضي للملف app/assets/stylesheets/scaffolds.scss عند توليد مورد جديد عبر المولد scaffold، يمكننا تعطيل scaffold_stylesheet:

config.generators do |g|
  g.scaffold_stylesheet false
end

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

config.generators do |g|
  g.orm             :active_record
  g.template_engine :erb
  g.test_framework  :test_unit, fixture: false
  g.stylesheets     false
  g.javascripts     false
end

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

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

$ bin/rails generate generator rails/my_helper
      create  lib/generators/rails/my_helper
      create  lib/generators/rails/my_helper/my_helper_generator.rb
      create  lib/generators/rails/my_helper/USAGE
      create  lib/generators/rails/my_helper/templates
      invoke  test_unit
      create    test/lib/generators/rails/my_helper_generator_test.rb

بعد ذلك، يمكننا حذف كلٍّ من المجلد templates وتابع الصنف class_root الذي يستدعى من المولد الجديد، لأننا لن نحتاج إليهما. أضف التابع أدناه، لذلك يبدو مولدنا كما يلي:

# lib/generators/rails/my_helper/my_helper_generator.rb
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
  def create_helper_file
    create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
module #{class_name}Helper
  attr_reader :#{plural_name}, :#{plural_name.singularize}
end
    FILE
  end
end

يمكننا تجربة مولدنا الجديد عن طريق إنشاء مساعد للمنتجات:

$ bin/rails generate my_helper products
      create  app/helpers/products_helper.rb

وسوف تولد الملف المساعد التالي في app/helpers:

module ProductsHelper

 attr_reader :products, :product

End

وهو ما كنا نتوقعه. يمكننا الآن أن نخبر المولد scaffold أن يستخدم المولد المساعد الجديد الخاص بنا عن طريق تعديل الملف config/application.rb مرة أخرى بالشكل التالي:

config.generators do |g|
  g.orm             :active_record
  g.template_engine :erb
  g.test_framework  :test_unit, fixture: false
  g.stylesheets     false
  g.javascripts     false
  g.helper          :my_helper
end

ونرى ذلك في العمل عند استدعاء المولد:

$ bin/rails generate scaffold Article body:text
      [...]
      invoke    my_helper
      create      app/helpers/articles_helper.rb

من المخرجات التي حصلنا عليها، يمكننا ملاحظة أن مساعدنا الجديد استُدعِي بدلًا من مولد ريلز الافتراضي. ومع ذلك، هناك شيء واحد مفقود، وهو الاختبارات لمولدنا الجديد؛ ولتصحيح ذلك، سنعيد استخدام مولدات الاختبار القديمة.

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

للقيام بذلك، يمكننا تغيير المولد بهذه الطريقة:

# lib/generators/rails/my_helper/my_helper_generator.rb
class Rails::MyHelperGenerator < Rails::Generators::NamedBase
  def create_helper_file
    create_file "app/helpers/#{file_name}_helper.rb", <<-FILE
module #{class_name}Helper
  attr_reader :#{plural_name}, :#{plural_name.singularize}
end
    FILE
  end
 
  hook_for :test_framework
end

الآن، عندما يُستدعَى المولد المساعد وتُكون TestUnit كإطار اختبار، سيحاول استدعاء Rails::TestUnitGenerator و TestUnit::MyHelperGenerator كلاهما. نظرًا لأنه لم يُعرَّف أي منها، يمكننا أن نطلب من المولد الخاص بنا استدعاء TestUnit::Generators::HelperGenerator بدلًا من ذلك، إذ هو مُعرَّف لأنه مولد ريلز. للقيام بذلك، نحن بحاجة فقط إلى إضافة:

# :my_helper بدلًا من :helper ابحث عن
hook_for :test_framework, as: :helper

والآن يمكنك إعادة تشغيل المولد scaffold لمورد آخر للتأكد من توليده للاختبارات أيضًا!

تخصيص سير العمل الخاص بك عن طريق تغيير قوالب المولدات

في الخطوة أعلاه، أردنا ببساطة إضافة سطر إلى المساعد الذي اُنشأ، دون إضافة أي وظائف إضافية. هناك طريقة أبسط للقيام بذلك، ومن خلال استبدال قوالب المولدات الموجودة بالفعل، في تلك الحالة Rails::Generators::HelperGenerator.

في الإصدار 3.0 وما بعده من ريلز، لا تبحث المولدات فقط في المصدر الأصل عن القوالب، بل تبحث أيضًا عن القوالب في مسارات أخرى. واحد منهم هو lib/templates. بما أننا نريد تخصيص Rails::Generators::HelperGenerator، يمكننا القيام بذلك ببساطة عن طريق إنشاء نسخة القالب داخل lib/templates/rails/helper بالاسم helper.rb. لذلك دعنا ننشئ هذا الملف مع المحتوى التالي:

module <%= class_name %>Helper
  attr_reader :<%= plural_name %>, :<%= plural_name.singularize %>
end

والرجوع إلى آخر تغيير في config/application.rb:

config.generators do |g|
  g.orm             :active_record
  g.template_engine :erb
  g.test_framework  :test_unit, fixture: false
  g.stylesheets     false
  g.javascripts     false
end

إذا قمت بإنشاء مورد آخر، يمكنك أن ترى أننا نحصل على نفس النتيجة بالضبط! وهذا مفيد إذا كنت تريد تخصيص قوالب المولد scaffold و/أو تخطيطك من خلال إنشاء edit.html.erb و index.html.erb وما إلى ذلك داخل lib/templates/erb/scaffold.

تستخدم قوالب المولد scaffold في ريلز وسوم ERB بشكل متكرر؛ هذه الوسوم تحتاج إلى أن تُهرَّب بحيث يكون الناتج الذي أنشأه وسم ERB صالح.

على سبيل المثال، سيكون الوسم ERB المهرَّب التالي مطلوبًا في القالب (لاحظ الإشارة % الزائدة) ...

<%%= stylesheet_include_tag :application %>

... لتوليد الناتج التالي:

<%= stylesheet_include_tag :application %>

إضافة تراجعات للمولدات

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

يمكننا بسهولة محاكاة هذا السلوك عن طريق تغيير config/application.rb الخاص بنا مرة أخرى:

config.generators do |g|
  g.orm             :active_record
  g.template_engine :erb
  g.test_framework  :shoulda, fixture: false
  g.stylesheets     false
  g.javascripts     false
 
  # إضافة تراجع
  g.fallbacks[:shoulda] = :test_unit
end

الآن، إذا أنشئت Comment عبر المولد scaffold، سترى أنه تُستدعَى المولدات shoulda، ثم يرجع إلى المولدات TestUnit في النهاية:

$ bin/rails generate scaffold Comment body:text
      invoke  active_record
      create    db/migrate/20130924143118_create_comments.rb
      create    app/models/comment.rb
      invoke    shoulda
      create      test/models/comment_test.rb
      create      test/fixtures/comments.yml
      invoke  resource_route
       route    resources :comments
      invoke  scaffold_controller
      create    app/controllers/comments_controller.rb
      invoke    erb
      create      app/views/comments
      create      app/views/comments/index.html.erb
      create      app/views/comments/edit.html.erb
      create      app/views/comments/show.html.erb
      create      app/views/comments/new.html.erb
      create      app/views/comments/_form.html.erb
      invoke    shoulda
      create      test/controllers/comments_controller_test.rb
      invoke    my_helper
      create      app/helpers/comments_helper.rb
      invoke    jbuilder
      create      app/views/comments/index.json.jbuilder
      create      app/views/comments/show.json.jbuilder
      invoke  test_unit
      create    test/application_system_test_case.rb
      create    test/system/comments_test.rb
      invoke  assets
      invoke    coffee
      create      app/assets/javascripts/comments.coffee
      invoke    scss

تسمح التراجعات للمولدات الخاصة بك بتحمل مسؤولية واحدة، مما يزيد من إعادة استخدام الشيفرات ويقلل من مقدار التكرار.

قوالب التطبيق

الآن بعد أن رأيت كيف يمكن استخدام المولدات داخل أحد التطبيقات، هل تعلم أيضًا أنه يمكن استخدامها أيضًا لإنشاء التطبيقات؟ يشار إلى هذا النوع من المولد باسم "قالب" (template). هذه نظرة عامة موجزة عن الواجهة Templates البرمجية. للحصول على التوثيق التفصيلي، انظر دليل قوالب تطبيقات ريلز.

gem "rspec-rails", group: "test"
gem "cucumber-rails", group: "test"
 
if yes?("Would you like to install Devise?")
  gem "devise"
  generate "devise:install"
  model_name = ask("What would you like the user model to be called? [user]")
  model_name = "user" if model_name.blank?
  generate "devise", model_name
end

في النموذج أعلاه، نحدد أن التطبيق يعتمد على الجوهرة rspec-rails والجوهرة cucumber-rails لذلك يُضافان إلى المجموعة test في الملف Gemfile.

ثم نطرح سؤالًا على المستخدم حول ما إذا كان يرغب في تثبيت Devise أم لا. إذا رد المستخدم "y" أو "yes" على هذا السؤال، سيضيف القالب Devise إلى الملف Gemfile خارج أي مجموعة، ثم يُشغل المولد devise: install.

ثم يأخذ هذا القالب مدخلات المستخدمين ويُشغل المولد devise، مع إجابة المستخدم من السؤال الأخير الذي مُرر إلى هذا المولد.

تخيل أن هذا القالب كان في ملف يسمى template.rb. يمكننا استخدامه لتعديل نتائج الأمر rails new باستخدام الخيار ‎-m وتمريره في اسم الملف:

$ rails new thud -m template.rb

سيولد هذا الأمر التطبيق Thud، ثم يطبق القالب إلى الناتج المولد.

لا يجب تخزين القوالب على النظام المحلي، كما يدعم الخيار ‎-m أيضًا النماذج عبر الإنترنت:

$ rails new thud -m https://gist.github.com/radar/722911/raw/

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

إضافة وسائط سطر الأوامر

يمكن تعديل مولدات ريلز بسهولة لقبول وسائط سطر الأوامر المخصصة. هذه الوظيفة تأتي من Thor:

class_option :scope, type: :string, default: 'read_products'

الآن يمكن استدعاء المولد الخاص بنا على النحو التالي:

rails generate initializer --scope write_products

يمكن الوصول إلى وسائط سطر الأوامر من خلال التابع options داخل صنف المولد مثل:

@scope = options['scope']

توابع المولد

فيما يلي التوابع المتوفرة لكل من المولدات والقوالب الخاصة بريلز.

ملاحظة: لا يُغطي هذا الدليل التوابع التي يقدمها Thor ويمكن العثور عليها في توثيق Thor.

gem

يحدد تبعية الجوهرة للتطبيق.

gem "rspec", group: "test", version: "2.1.0"
gem "devise", "1.1.5"

الخيارات المتاحة هي:

  • group:‎ - المجموعة في الملف Gemfile حيث يجب أن تذهب هذه الجوهرة.
  • version:‎ - سلسلة إصدار الجوهرة التي تريد استخدامها. يمكن أيضًا تحديده كوسيطٍ ثانٍ للتابع.
  • git:‎ - عنوان URL لمستودع git لهذه الجوهرة.

تُوضع أي خيارات إضافية مُررت إلى هذا التابع في نهاية السطر:

gem "devise", git: "https://github.com/plataformatec/devise.git", branch: "master"

ستضع الشيفرة السابقة السطر التالي في الملف Gemfile:

gem "devise", git: "https://github.com/plataformatec/devise.git", branch: "master"

gem_group

يغلف مدخلات الجوهرة داخل المجموعة:

gem_group :development, :test do
  gem "rspec-rails"
end

add_source

يضيف مصدرًا محددًا إلى الملف Gemfile:

add_source "http://gems.github.com"

هذا التابع يأخذ أيضا كتلة:

add_source "http://gems.github.com" do
  gem "rspec-rails"
end

inject_into_file

يحقن كتلة من التعليمات البرمجية في موضع محدد في ملفك.

inject_into_file 'name_of_file.rb', after: "#The code goes below this line. Don't forget the Line break at the end\n" do <<-'RUBY'
  puts "Hello World"
RUBY
end

gsub_file

يستبدل نصًّا داخل الملف.

gsub_file 'name_of_file.rb', 'method.to_be_replaced', 'method.the_replacing_code'

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

application

يضيف سطرًا إلى config/application.rb مباشرةً بعد تعريف صنف التطبيق.

application "config.asset_host = 'http://example.com'"

يمكن أن يأخذ هذا التابع أيضًا كتلة:

application do
  "config.asset_host = 'http://example.com'"
end

الخيارات المتاحة هي:

  • env:‎ - حدد بيئة لخيار التوصيف هذا. إذا كنت ترغب في استخدام هذا الخيار مع صياغة الكتلة، تكون الصياغة الموصى بها كما يلي:
application(nil, env: "development") do
  "config.asset_host = 'http://localhost:3000'"
end

git

يشغل الأمر git المحدد:

git :init
git add: "."
git commit: "-m First commit!"
git add: "onefile.rb", rm: "badfile.cxx"

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

vendor

يضع ملفًا في vendor الذي يحتوي على الشيفرة المحددة.

vendor "sekrit.rb", '#top secret stuff'

هذا التابع يأخذ أيضا كتلة:

vendor "seeds.rb" do
  "puts 'in your app, seeding your database'"
end

lib

يضع ملفًا في lib يحتوي على الشيفرة المحددة.

lib "special.rb", "p Rails.root"

هذا التابع يأخذ أيضا كتلة:

lib "super_special.rb" do
  "puts 'Super special!'"
end

rakefile

ينشئ ملف Rake في دليل lib/tasks الخاص بالتطبيق.

rakefile "test.rake", 'task(:hello) { puts "Hello, there" }'

هذا التابع يأخذ أيضا كتلة:

rakefile "test.rake" do
  %Q{
    task rock: :environment do
      puts "Rockin'"
    end
  }
end

initializer

ينشئ مُهيئ في المجلد config/initializers للتطبيق:

initializer "begin.rb", "puts 'this is the beginning'"

يأخذ هذا التابع أيضًا كتلة، ويتوقع أن يعيد سلسلة نصية:

initializer "begin.rb" do
  "puts 'this is the beginning'"
end

generate

يشغِّل المولد المحدد حيث يكون الوسيط الأولى هو اسم المولد وتمرر الوسائط المتبقية مباشرة إلى المولد.

generate "scaffold", "forums title:string description:text"

rake

يشغل مهمة Rake محددة.

rake "db:migrate"

الخيارات المتاحة هي:

  • env:‎  - يحدد البيئة التي ستشغل مهمة rake.
  • sudo:‎ - يحدد تشغيل هذه المهمة باستخدام sudo أم لا. القيمة الافتراضية هي: false.

route

يضيف نصًا إلى الملف config/routes.rb:

route "resources :people"

readme

يطبع محتويات الملف في source_path للقالب، عادة ما يكون README.

readme "README"

مصادر