Application Controller中的引擎路由

时间:2011-09-28 19:58:18

标签: ruby-on-rails-3 rails-routing rails-engines

我的主应用程序的应用程序控制器中有一个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的布局中,那么这个问题也会在那里出现。

5 个答案:

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

  3. 如果您正在寻找引擎上的文档,rails docs for the Engine class是一个非常好的起点。如果您对该主题感兴趣,我强烈建议您阅读它们(如果您还没有)。

答案 1 :(得分: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的做法。

答案 2 :(得分: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

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

答案 3 :(得分:0)

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

[MyEngine::Engine, App::Application].each do |app|
  app.routes.draw do
    # Declare all your routes here
  end
end

答案 4 :(得分:0)

您可以保留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,这都是可以预期的。