13

我的主应用程序的应用程序控制器中有一个 before_filter 钩子,它执行以下操作:(它不只是在闪存中放置一个链接,还有一条消息,但它与问题无关,它只是访问路径方法)

class ApplicationController < ActionController::Base
  before_filter :set_link

  def set_link
    flash[:notice] = items_path
  end
end

这适用于该应用程序,但是当我进入我制作的引擎的控制器时,我得到了异常

No route matches {:controller=>"items", :action=>"index"}

我知道在引擎中,除非前缀为main_app

因此将应用程序控制器中的方法更改为

  def set_link
    flash[:notice] = main_app.items_path
  end

摆脱异常,但我真的不想这样做。是否有另一种解决方案可以让引擎识别 main_app 路线?

编辑:

如果应用程序布局调用路径助手,也会发生这种情况。因此,如果引擎被设计为集成到 main_app 的布局中,那么这个问题也会在那里出现。

4

5 回答 5

19

可挂载引擎被设计成这样工作,即隔离主应用程序路由和引擎路由。

如果要合并两组路由,可以使用非隔离引擎。第一步是删除isolated_namespace引擎定义中的方法调用:

module MyEngine
  class Engine < Rails::Engine
    isolate_namespace MyEngine # remove this line
  end
end

第二步是转换你的路线my_engine/config/routes.rb,你应该从这个开始:

MyEngine::Engine.routes.draw do
  # stuff that routes things
end

对此:

Rails.application.routes.draw do
  # stuff that routes things
end

并删除mount应用程序路由中的方法调用:

App::Application.routes.draw do
  mount MyEngine::Engine => "/engine" # remove this line
end

这样做的主要优点是:

  1. 无需猴子修补铁轨。我知道设计可以做到这一点,但这可能是轨道中不存在引擎的日子的遗留物。

  2. 无需在应用程序路径中安装引擎。另一方面,如果您想更精确地控制插入点,这可能会适得其反,因为您的所有引擎路线都将在您的主要路线之后(或之前,我没有这个问题的答案)被调用。

如果您正在寻找有关引擎的文档,Engine 类的 rails 文档是一个很好的起点。如果您对该主题感兴趣,我强烈建议您阅读它们(如果您还没有)。

于 2011-10-01T20:25:24.703 回答
4

我想出了如何做到这一点。问题在于隔离的命名空间。为了将引擎与应用程序集成并共享相同的布局(可能有来自主应用程序的路径助手),我这样做了:

首先我config/routes.rb从引擎中取出

然后我从引擎类中删除了isolate_namespace

module MyEngine
   class Engine < Rails::Engine
-    isolate_namespace MyEngine
   end
 end
end

我添加了一个加载到引擎中的文件:

module ActionDispatch::Routing
  class Mapper
    def mount_my_engine_at(mount_location)
      scope mount_location do
        #Declare all your routes here
      end
    end
  end
end

最后,在主应用程序config/routes.rb中,您可以调用您的方法,而不是“安装”引擎

mount_my_engine_at "mount_location"

这基本上会将您的引擎“安装”为主应用程序的一部分,而不是与其隔离。它也类似于 Devise 的做法。

于 2011-09-30T17:16:00.007 回答
2

您可以保留isolate_namespace。在你的引擎 routes.rb

MyEngine::Engine.routes.draw do
  ...
  root to: "something#index"
end

Rails.application.routes.draw do
  get "something", to: "my_engine/something#index"
end

然后在主应用 routes.rb

Rails.application.routes.draw do

  mount MyEngine::Engine => "/anything_you_want"

  root to: "main#index"
end

通过这种方式,您可以选择要公开的路线(以及不公开的路线)

于 2013-04-21T02:51:06.497 回答
1

您可以按照 Rails Engine 指南强烈推荐的方式保留 isolate_namespace,并执行以下操作:

# inside your main_app's config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'

  mount MyEngine::Engine, at: "/" 
end
# inside your engine's controller
module MyEngine
  class SomeController << ::ApplicationController
    # include main_app's route helpers
    helper Rails.application.routes.url_helpers

  end
end

在您的 gem 中,确保所有 url 助手都以正确的路由代理方法为前缀(例如 my_engine.pages_path)。

您的 main_app 的布局和引擎的控制器将正确路由并链接到这些 url 助手到主应用程序。您不必在主应用程序的任何位置添加“main_app”前缀。唯一的缺点是您将引擎的路由安装在 main_app 的根路径上,这可能会与任何同名的路由发生冲突。如果您要执行非isolate_namespace,这无论如何都是意料之中的。

于 2019-12-03T21:33:58.890 回答
0

最简单的方法是在主应用程序和引擎中绘制路线,以便两者都可以访问它们:

[MyEngine::Engine, App::Application].each do |app|
  app.routes.draw do
    # Declare all your routes here
  end
end
于 2012-07-25T16:53:35.443 回答