{"id":2854,"date":"2016-01-30T10:01:17","date_gmt":"2016-01-30T09:01:17","guid":{"rendered":"https:\/\/sgaul.de\/?p=2854"},"modified":"2016-01-30T15:20:20","modified_gmt":"2016-01-30T14:20:20","slug":"rails-konfiguration-in-engine-auslagern","status":"publish","type":"post","link":"https:\/\/sgaul.de\/2016\/01\/30\/rails-konfiguration-in-engine-auslagern\/","title":{"rendered":"Rails-Konfiguration in Engine auslagern"},"content":{"rendered":"

F\u00fcr die meisten Rails-Projekte verwende ich die gleichen Gems mit \u00e4hnlichen Konfigurationen. Um den Projektstart und den Update-Prozess zu vereinheitlichen, m\u00f6chte\u00a0ich eine Engine, die diese\u00a0Abh\u00e4ngigkeiten und Konfigurationen \u00fcbernimmt.<\/p>\n

F\u00fcr den einfacheren Einstieg erzeuge\u00a0ich innerhalb einer bestehenden Rails-App eine neue Engine:<\/p>\n

rails plugin new m3 --full<\/pre>\n

Diese wird zu Testzwecken im Gemfile des Elternprojekts verlinkt:<\/p>\n

gem 'm3', path: 'm3'<\/pre>\n

<\/p>\n

Gem-Abh\u00e4ngigkeiten im Gemspec-File<\/h2>\n

Im Gemspec-File m3.gemspec steht bereits eine Rails-Abh\u00e4ngigkeit, die ich um die gew\u00fcnschten Gems erweitere:<\/p>\n

s.add_dependency \"rails\", \"~> 4.2.4\"\r\ns.add_dependency \"simple_form\", \"~> 3.2.0\"\r\ns.add_dependency \"draper\", \"~> 2.1.0\"\r\ns.add_dependency \"cancancan\", \"~> 1.13.1\"<\/pre>\n

Damit diese beim Start der Elternapplikation zur Verf\u00fcgung stehen, m\u00fcssen diese vom Gem geladen werden. Dies sollte in der Engine-Datei gemacht werden:<\/p>\n

# <gem>\/lib\/<gem>\/engine.rb\r\n\r\nrequire 'cancan'\r\nrequire 'draper'\r\nrequire 'simple_form'\r\n\r\nmodule M3\r\n  class Engine < ::Rails::Engine\r\n    # ...<\/pre>\n

Die Elternapplikation kann nun wie gewohnt auf die Gems zugreifen.<\/p>\n

Initializer<\/h2>\n

Erweiterte Konfigurationen f\u00fcr Simple-Form werden in zugeh\u00f6rigen Initializern festgelegt, die man ebenfalls einfach in der Engine anlegen kann:<\/p>\n

# <gem>\/config\/initializers\/simple_form.rb\r\n\r\nSimpleForm.setup do |config|\r\n  # ...<\/pre>\n
# <gem>\/config\/initializers\/simple_form_bootstrap.rb\r\n\r\nSimpleForm.setup do |config|\r\n # ...<\/pre>\n

Controller-Erweiterungen<\/h2>\n

Grundlegende Controller-Konfigurationen habe ich in einen Application-Controller mit Namespace gepackt:<\/p>\n

# <gem>\/app\/controllers\/m3\/application_controller.rb\r\n\r\nclass M3::ApplicationController < ActionController::Base\r\n  # ...<\/pre>\n

Hier kann man auch wie gewohnt Concerns verwenden, diese werden ebenfalls automatisch gefunden.<\/p>\n

Die\u00a0fertigen Konfigurationen\u00a0k\u00f6nnen dann vom Application-Controller der Elternapplikation verwendet werden:<\/p>\n

# <app>\/app\/controllers\/application_controller.rb\r\n\r\nclass ApplicationController < M3::ApplicationController\r\n  # ...<\/pre>\n

Module und Klassen aus lib bereitstellen<\/h2>\n

Auch in einer Engine landet unter lib so einiges, was nicht vom Autoloading abgedeckt wird. Diese k\u00f6nnten\u00a0wie Gem-Abh\u00e4ngigkeiten explizit in der Engine-Datei geladen werden. Diese L\u00f6sung ist jedoch ein unsch\u00f6ner Workaround und sei hier nur f\u00fcr den Notfall aufgef\u00fchrt.<\/p>\n

# <gem>\/lib\/<gem>\/engine.rb\r\n# Workaround\r\nrequire_dependency File.expand_path(\"..\/..\/..\/app\/models\/m3\", __FILE__)\r\nrequire_dependency File.expand_path(\"..\/..\/..\/lib\/m3\/router\", __FILE__)<\/pre>\n

Wie man sieht lade ich hier auch den Namespace M3, da Autoloading an dieser Stelle noch nicht funktioniert und die Lib-Klasse Routes entweder aufgrund des fehlenden Namespaces knallt oder diesen als leeres Modul anlegt. Letzteres kann zu einem schwer zu findenden Fehler f\u00fchren, da\u00a0die Modul-Datei im Verzeichnis\u00a0app dann gar nicht mehr geladen wird.<\/p>\n

Wie angedeutet ist dieser Ansatz wenig elegant.\u00a0Die Require-Statements sollten besser\u00a0zu einem Zeitpunkt ausgef\u00fchrt werden, an dem Autoloading bereits zur Verf\u00fcgung steht. Dann passiert vieles automatisch und \u00fcbrige Requires k\u00f6nnen ohne File-Path-Expansions notiert werden:<\/p>\n

# <gem>\/lib\/m3\/router.rb\r\n\r\nrequire_dependency 'm3'\r\n\r\nclass M3::Router\r\n  # ...<\/pre>\n
# <gem>\/config\/routes.rb\r\n\r\nrequire_dependency 'm3\/router'\r\n\r\nRails.application.routes.draw do\r\n  M3::Router.draw_routes(self)\r\nend<\/pre>\n","protected":false},"excerpt":{"rendered":"

F\u00fcr die meisten Rails-Projekte verwende ich die gleichen Gems mit \u00e4hnlichen Konfigurationen. Um den Projektstart und den Update-Prozess zu vereinheitlichen, m\u00f6chte\u00a0ich eine Engine, die diese\u00a0Abh\u00e4ngigkeiten und Konfigurationen \u00fcbernimmt. F\u00fcr den einfacheren Einstieg erzeuge\u00a0ich innerhalb einer bestehenden Rails-App eine neue Engine: rails plugin new m3 –full Diese wird zu Testzwecken im Gemfile des Elternprojekts verlinkt: gem… Rails-Konfiguration in Engine auslagern<\/span> weiterlesen<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":[],"categories":[91],"tags":[579,527,553,552],"_links":{"self":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/2854"}],"collection":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/comments?post=2854"}],"version-history":[{"count":9,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/2854\/revisions"}],"predecessor-version":[{"id":2864,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/posts\/2854\/revisions\/2864"}],"wp:attachment":[{"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/media?parent=2854"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/categories?post=2854"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/sgaul.de\/wp-json\/wp\/v2\/tags?post=2854"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}