在主应用程序中删除路径助手中对main_app前缀的需要

时间:2014-11-18 11:00:22

标签: ruby-on-rails-4 rails-engines

我有一个可隔离的可安装的rails引擎,它将自己安装在已在宿主应用程序中声明的命名空间中。以下是它的外观或多或少:

插件中的routes.rb:

# my_engine/config/routes.rb 
MyEngine::Engine.routes.draw do
  namespace :admin do
    resources :some_resource
  end
end

来自主机应用的routes.rb:

的相应代码段
# config/routes.rb
mount MyEngine::Engine, at: "/"

namespace :admin do
  resources :host_resource
end

我正在/安装引擎,因为引擎中有一些应该可用的路由,并且管理命名空间重叠是故意的。

这些路由生成多个路径助手,包括my_engine.admin_some_resources_path以及我期望的admin_host_resources_path。后者是不起作用的。

假设主应用程序中有一个声明如此声明的控制器:

# app/controllers/admin/application_controller.rb
class Admin::ApplicationController < ApplicationController
  layout 'admin'
end

引擎的AdminController以继承它的方式声明:

# my_engine/app/controlles/admin/application_controller.rb
class MyEngine::Admin::ApplicationController < Admin::ApplicationController
end

到目前为止,所有这些都按预期工作。现在,假设在主应用程序的admin布局中,从Admin :: ApplicationController引用,我尝试使用基本上类似的东西:

# app/views/layouts/admin.html.erb
<%= link_to "Host resources", admin_host_resources_path %>
<%= link_to "Plugin's resources", my_engine.admin_some_resources_path %>

当我加载像'/ admin / host_resources'这样的路径时,这工作正常 - 它从主应用程序呈现管理布局没问题。当打开路径'/ admin / some_resources'(进入插件)时,它会停止工作,抱怨找不到admin_host_resources_path。当我将其更改为此时,它开始工作:

# app/views/layouts/admin.html.erb
<%= link_to "Host resources", main_app.admin_host_resources_path %>
<%= link_to "Plugin's resources", my_engine.admin_some_resources_path %>

这不是我想要的,也不是我所期待的。此外,我已经看到足够的rails插件知道这不应该是必要的,但在阅读了Engines文档后,我仍然不知所措。我也在搜索Stack,但无济于事。我的问题是:如何包含main_app助手,以便不再需要前缀main_app

值得注意的是,host_resource的视图位于主应用程序本身,而some_resource的视图位于引擎中。但这并不重要,因为不起作用的视图是主应用程序中的admin布局。

也请原谅严重匿名的代码,但这是我的要求。

2 个答案:

答案 0 :(得分:2)

在控制器中添加:

helper Rails.application.routes.url_helpers

答案 1 :(得分:1)

我在这里找到了一个问题的答案:http://candland.net/2012/04/17/rails-routes-used-in-an-isolated-engine/

我需要做的是在引擎中指定这样的帮助器:

module MyEngine
  module ApplicationHelper
    def method_missing method, *args, &block
      if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
        if main_app.respond_to?(method)
          main_app.send(method, *args)
        else
          super
        end
      else
        super
      end
    end

    def respond_to?(method)
      if method.to_s.end_with?('_path') or method.to_s.end_with?('_url')
        if main_app.respond_to?(method)
          true
        else
          super
        end
      else
        super
      end
    end
  end
end

然后通过将其添加到我的引擎类中来确保在加载引擎时加载它:

initializer 'my_engine.action_controller' do |app|
  ActiveSupport.on_load :action_controller do
    helper MyEngine::ApplicationHelper
  end
end

由于这个原因,引擎可以提供的路径由引擎提供,其他所有路径都会发送到main_app助手。