装饰Rails引擎的帮助程序以包含来自主应用程序的关注点

时间:2019-01-09 14:08:42

标签: ruby-on-rails ruby

我想通过装饰引擎的帮助程序模块之一,将ActiveSupport :: Concern包含在引擎中。 这是引擎的帮助程序:

module MyEngine
  module MyHelper
  end
end

这是主应用程序中的问题:

module MyConcern
  extend ActiveSupport::Concern

  def do_this
  end

  def do_that
  end
end

下面是经过修饰的引擎帮助程序,需要包括关注事项(用于引擎视图)-在主应用程序中使用{{3}中所述的修饰符模式进行声明}:

module MyEngine
  module MyHelper
    include MyConcern

    def do_stuff
    end
  end
end

装饰正确的帮助程序已由引擎正确加载,但是引擎视图只能调用“ do_stuff”。 MyConcern的方法不可用,我很难找出原因。 我还尝试通过将其嵌入MyEngine :: MyHelper.module_eval调用中来包含此问题,但这也不起作用。

以前有人遇到过这种问题吗?我采取这种错误的方式吗?

3 个答案:

答案 0 :(得分:0)

我将MyHelper从模块重新放置到类

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

致电时:

MyEngine::MyHelper.new.do_stuff
MyEngine::MyHelper.new.do_this
MyEngine::MyHelper.new.do_that

结果将是:

  

做事

     

执行此操作

     

这样做

答案 1 :(得分:0)

我认为您可能对此事有所反省。

如果您的引擎提供:

module MyEngine
  module MyHelper
    def foo
    end
  end
end

您可以在主应用程序中扩展该方法(您可以称其为decorate,但我不确定这在技术上是否是装饰器模式):

module MainApp
  module MyHelper
    extend ::MyEngine::MyHelper
    def foo
      super
      do_something_else
    end
  end
end

在使用模块混合模式(ActiveSupport :: Concern所做的事情)时,将模块扩展为模块,并将模块包括在类中。

如果引擎和主应用程序“共享部分”,则应将其放置在引擎中,因为Rails在渲染应用程序的app / views目录时会先寻找该视图,然后再查找已安装的引擎。

因此,主应用程序始终可以覆盖引擎提供的功能,而反之则不成立。

如果要使引擎提供的方法可配置,更好的主意是使用Rails配置设置(或单独的模块配置)或仅使用方法参数,而不是使用一些疯狂的循环依赖马戏团。

答案 2 :(得分:0)

所以我终于找到了一种“干净”的方法,如以下评论所述:https://groups.google.com/g/rubyonrails-core/c/PaABJDXnxyo/m/k-QUJEi9a9wJ

这个想法是在引擎中添加一个空的占位符助手,例如:

module MyEngine
  module ExtendableHelper
  end
end

然后通过添加方法或添加关注点,其他gem的助手等在主应用中将其覆盖...

module MyEngine
  module ExtendableHelper
    extend OtherGemFromMainApp::UsefulHelper
    include MainAppConcern
    
    def other_useful_method
      ...
    end
  end
end

因此,引擎使用的助手是应用程序提供的助手,并且可以在引擎视图中调用 UsefulHelper 方法。