Je voudrais inclure un ActiveSupport :: Concern d'une application dans un moteur, en décorant l'un des modules d'aide du moteur. Voici le Helper du moteur:
module MyEngine
module MyHelper
include MyConcern
def do_stuff
end
end
end
Voici le souci de l'application principale:
module MyConcern extend ActiveSupport::Concern def do_this end def do_that end end
Ci-dessous se trouve l'assistant de moteur décoré qui doit inclure le problème (à utiliser dans les vues du moteur) - il est déclaré dans l ' application principale , en utilisant le modèle de décorateur décrit dans le Guides de rails :
module MyEngine module MyHelper end end
L'assistant décoré est correctement chargé par le engine, mais les vues du moteur ne peuvent appeler que "do_stuff". Les méthodes de MyConcern ne sont pas disponibles et j'ai du mal à comprendre pourquoi. J'ai également essayé d'inclure le problème en l'incorporant dans un appel MyEngine :: MyHelper.module_eval, mais cela n'a pas fonctionné non plus.
Est-ce que quelqu'un a déjà rencontré ce genre de problème? Est-ce que je prends cela dans le mauvais sens?
3 Réponses :
J'ai remplacé MyHelper du module à la classe
MyEngine::MyHelper.new.do_stuff MyEngine::MyHelper.new.do_this MyEngine::MyHelper.new.do_that
Lors de l'appel:
module MyConcern
extend ActiveSupport::Concern
def do_this
"do this"
end
def do_that
"do that"
end
end
module MyEngine
class MyHelper
include ::MyConcern
def do_stuff
"do stuff"
end
end
end
Le résultat sera:
faire des choses
faites ceci
fais ça
Salut @Xero, merci pour votre réponse. Malheureusement, l'utilisation d'une classe n'est pas une option ici, car Rails nécessite que les helpers soient déclarés en tant que modules afin de les inclure dans le contexte des vues.
Je pense que vous raisonnez peut-être à ce sujet à l'envers.
Si votre moteur fournit:
module MainApp
module MyHelper
extend ::MyEngine::MyHelper
def foo
super
do_something_else
end
end
end
Vous pouvez étendre la méthode (vous pouvez l'appeler decorate mais i ' Je ne sais pas si c'est techniquement le modèle de décorateur) dans votre application principale:
module MyEngine
module MyHelper
def foo
end
end
end
Lorsque vous utilisez le modèle module-mixin (ce que fait ActiveSupport :: Concern), vous étendez modules avec des modules et inclure des modules dans les classes.
Si votre moteur et votre application principale "partagent une partie" - il doit simplement être placé dans le moteur car Rails cherchera d'abord la vue lors du rendu dans le répertoire app / views de l'application avant de la rechercher les moteurs montés.
L'application principale peut donc toujours remplacer la fonctionnalité fournie par le moteur alors que l'inverse n'est pas vrai.
Si vous voulez rendre configurable une méthode fournie par un moteur, une meilleure idée est pour utiliser un paramètre de configuration Rails (ou une configuration de module séparée) ou simplement des arguments de méthode plutôt qu'un cirque de dépendance circulaire fou.
Merci pour l'explication détaillée. Cela devient plus clair, mais ce n'est pas tout à fait le même cas d'utilisation: mon module ActiveSupport :: Concern fournit des méthodes pour générer des liens de navigation. Ces liens sont rendus dans le "top nav partial", à la fois dans l'application principale et dans les vues du moteur (les vues savent quel partiel utiliser avec un paramètre de configuration, comme suggéré). Lorsque j'étends l'assistant de moteur et que j'y ajoute explicitement des méthodes, cela fonctionne. Cependant, si j'essaie d'inclure un autre module (les liens de navigation déjà déclarés dans une préoccupation), les méthodes ne sont pas disponibles pour le moteur.
J'ai donc finalement trouvé un moyen de faire cela de manière "propre", comme mentionné dans le commentaire suivant: https://groups.google.com/g/rubyonrails-core/c/PaABJDXnxyo/m/k-QUJEi9a9wJ
L'idée est de ajoutez un assistant d'espace réservé vide dans le moteur, par exemple:
module MyEngine
module ExtendableHelper
extend OtherGemFromMainApp::UsefulHelper
include MainAppConcern
def other_useful_method
...
end
end
end
Et puis remplacez-le dans l'application principale, en ajoutant des méthodes ou en incluant des préoccupations, des helpers d'autres gemmes, etc. ..
module MyEngine module ExtendableHelper end end
Ainsi, l'aide utilisée par le moteur est celle fournie par l'application, et les méthodes UsefulHelper peuvent être appelées dans les vues du moteur .
ma réponse correspond-elle à vos exigences? sinon, veuillez compléter votre question
"Est-ce que je prends ça dans le mauvais sens?" - oui très probablement. L'idée est qu'un moteur doit encapsuler une fonctionnalité réutilisable. Bien qu'un moteur puisse s'appuyer sur l'application parente pour l'implémentation réelle (comme Devise par exemple), il ne devrait généralement pas avoir de dépendance stricte sur l'application parente, car cela rendrait très difficile de tester le moteur isolément ou de le réutiliser. Cela rend tout le processus d'extraction de la fonctionnalité inutile.
@max merci pour les commentaires, je suis d'accord qu'un moteur ne devrait pas avoir de dépendances sur l'application hôte. C'est pourquoi j'ai choisi de décorer l'assistant du côté de l'application principale, ce qui n'est pas une "dépendance dure" je crois, mais plutôt une injection de dépendance fournie par l'application principale pour personnaliser l'assistant du moteur. Le but ici est d'utiliser les méthodes Concern do_this et do_that dans la vue du moteur, car il partage un partiel commun avec l'application principale (généralement un volet de navigation supérieur avec des liens).
Donc, fondamentalement, ce que vous voulez vraiment faire est de déclarer un module dans votre application principale qui étend le module du moteur et non l'inverse. Notez que vous souhaitez utiliser extend et ne pas inclure lorsque vous ajoutez des méthodes à un module.
@max J'ai édité la question pour clarifier car je me rends compte que mon utilisation du modèle de décorateur n'était pas claire. J'ai déclaré l'assistant décoré du côté de l'application principale, et les méthodes déclarées directement sont disponibles dans le moteur. Ce qui ne fonctionne pas pour moi, c'est lorsque j'essaye d'inclure un module ActiveSupport :: Concern (également de l'application principale) dans cet assistant décoré.