在隔离的 Rails 引擎中从父应用程序访问助手

Accessing helpers from the parent app in an isolated Rails engine

我正在编写一个可配置的 Rails 引擎。我有一个 authentication_helper 配置选项来定义在所有需要身份验证的控制器的 before_action 中应该调用哪个助手。

问题是我无法从引擎的控制器访问父应用程序的助手。 My understanding是因为引擎被隔离了才会出现这种情况。

我考虑过使用块而不是方法名称,但我不确定这是否可行,或者我是否能够从我的控制器外部干净地访问授权逻辑。

Active Admin,我过去用过,也有类似的配置选项。我注意到他们的引擎不是隔离的,所以也许我高估了引擎隔离的重要性?

有没有一种优雅的方式既可以享受引擎隔离的好处,又可以进行这种自定义?还是我应该完全放弃隔离?

编辑#1

Brad Werth 为我指出了正确的方向,因为这适用于继承自 ApplicationController::Base:

的常规控制器
module MyBigFancyEngine
  class Engine < Rails::Engine

    isolate_namespace MyBigFancyEngine  

    config.to_prepare do
      # Make the implementing application's helpers available to the engine.
      # This is required for the overriding of engine views and helpers to work correctly.
      MyBigFancyEngine::ApplicationController.helper Rails.application.helpers
    end

  end
end

然而,我的引擎的 ApplicationController 继承自 RocketPant::Base,它不提供 helper 方法。我试过使用一个简单的 include(对于常规控制器工作正常),但这也不起作用(控制器找不到助手)。

有什么想法吗?

我认为你保持隔离的冲动是好的 - 因为如果 s.th 依赖方法 'just being there' 的解决方案很难调试。使用您的 gem 的应用程序出错(即方法名称中的拼写错误)。

此外,如果您的 gem 有所发展,总有一天它不需要该方法,以一种明确的方式给出有意义的错误非常方便:

您可以提供一个在初始化程序中调用的配置方法:

YourGem.configure do |config|
  config.add_callback { MyApp.doIt() }
end

我在 Isolated engine helpers 下找到了这个 discussion particularly insightful. There are also some interesting ideas in the Rails Engine API

Rails 引擎 API 文档帮助我找到了 url_helpers

的良好解决方案

您可以通过在 engine.rb 文件中包含以下代码来公开引擎可用的实施应用程序助手:

engine.rb

module MyBigFancyEngine
  class Engine < Rails::Engine

    isolate_namespace MyBigFancyEngine  

    config.to_prepare do
      # Make the implementing application's helpers available to the engine.
      # This is required for the overriding of engine views and helpers to work correctly.
      MyBigFancyEngine::ApplicationController.helper Rails.application.helpers
    end

  end
end

Rails管理引擎也是独立的,但它们具有与您希望实现的相同的配置选项。他们具有可配置的 before_filters 用于身份验证和授权。看看 this.

据我所知,它们只是像这样子类化父控制器::ApplicationController,或者您可以配置一个 (ref)。

对于您的控制器,您可以创建自己的 EngineController,它继承自 RocketPant::Base,并且可能只是在那里创建一个方法,通过 send 直接调用配置的身份验证方法父控制器。

因为 RocketPant::Base Class 没有继承自 ApplicationController::Base 我想你必须找到一些自定义的方法来解决这个问题并且不能使用 [=32= 的正常方法] 引擎。也许您也可以尝试向 rocket_pant 存储库提交问题,以添加 helper 方法。据我所知,他们很快就想在 2.0 (ref) 中继承 ApplicationController::Base

您现在可能继续前进,但如果其他人需要访问 "parent app" 应用程序助手。您总是可以将它显式地包含在引擎的应用程序控制器中。像这样:

include Rails.application.helpers