2017-01-05 2 views
4

In unserem Verzeichnis app möchten wir, dass einige der Unterverzeichnisse Namespace-Klassen enthalten und einige, die Klassen der obersten Ebene enthalten. Zum Beispiel:Namensraum innerhalb des `app`-Verzeichnisses

  • app/models/user.rb definiert ::User
  • app/operations/foo.rb definiert ::Operations::Foo
  • app/operations/user/foo.rb::Operations::User::Foo

Unsere application.rb enthält die folgende Konfiguration definiert:

config.paths = Rails::Paths::Root.new(Rails.root) 
config.paths.add 'app/models', eager_load: true 
config.paths.add 'app', eager_load: true 

Dies funktioniert in den meisten Fällen gut, aber manchmal im Entwicklungsmodus und mit aktiviertem Autorespeichern von Rails führt dies dazu, dass falsche Klassen geladen werden. Zum Beispiel wird ::User mit Operations::User verwechselt und umgekehrt.

Gibt es eine Möglichkeit, dieses Verhalten so zu konfigurieren, dass es fehlerfrei funktioniert?

Wenn nicht, ist die einzige Problemumgehung, die ich denken kann, ein zweites Verzeichnis für "namespaced" Klassen in den Zeilen app und app_namespaced zu erstellen. Oder sonst app/namespaced, da der Code auf App-Ebene innerhalb von app liegen sollte. Aber diese scheinen für mich wie hässliche Umwege zu sein.

Edit: Ein kleines Beispiel wie von @dgilperez gestellt:

# app/models/user.rb 
class User 
end 

# app/models/group.rb 
class Group 
    def some_method 
    # Since we're in a top-level namespace, User should always 
    # resolve to ::User. But, depending on some seemingly random 
    # factors, it sometimes resolves to Operations::User. 
    User.new 
    end 
end 

# app/operations.rb 
module Operations 
end 

# app/operations/user/create.rb 
module Operations::User 
    class Create 
    def some_method 
     # Here, as expected, I need to prefix with "::" as 
     # 'User' would refer to the module we're currently in. 
     # That's fine and works. 
     ::User.new 
    end 
    end 
end 
+1

Sie voll qualifizierte Konstanten verwenden könnten oder 'require_dependency' wie in [Wenn Konstanten werden nicht verschossen] (http://guides.rubyonrails.org/autoloading_and_reloading_constants.html#when-constants-aren-t- verpasst) – Stefan

+0

Kannst du die Definition der Klassen einfügen? Und der Code, der die Verwirrung verursacht (Anruf und Standort) – dgilperez

+0

Danke für den Blick in diese @ dgilperez, ich habe gerade ein kleines Beispiel hinzugefügt. – Remo

Antwort

0

Ja, das ist ein Nachteil von autoloading Schienen. Standardmäßig lädt es alles von /app, aber die erste Ebene der Verzeichnisstruktur ist nicht Teil der Namen. Es ist so, dass app/models/user.rbUser definieren kann, nicht erforderlich, dass es ist.

Sie müssen sich nicht mit den Lastpfaden anlegen. Mehrere Ansätze/Workarounds sind hier verfügbar.

  1. In meinem aktuellen Projekt verdoppeln wir nur das Namespacing-Verzeichnis. Was bedeutet, dass, wenn wir ServiceObjects::User::Import definieren wollen, setzen wir es in app/service_objects/service_objects/user/import.rb

  2. ich persönlich eine Variation dieses Ansatzes bevorzugen, die alle „non-standard“ Sachen in app/lib zu setzen ist (kann sein app/custom oder alles, was Sie wollen) . Auf diese Weise gibt es keine seltsame Duplizierung von Verzeichnisnamen und der gesamte benutzerdefinierte Code ist schön enthalten.

Verwandte Themen