控制从发动机装载订单的路线

Gro*_*ery 15 ruby-on-rails-3

所以在Rails3引擎中有自己的模型/控制器/视图,当然还有路由.现在的问题是:如何确保在应用程序路由之前(或之后)以及所有其他引擎上加载引擎路由?

这是我的Rails应用程序路由的示例:

match '*(path)', :to => 'foo_controller#bar_action'
Run Code Online (Sandbox Code Playgroud)

我的引擎:

match '/news', :to => 'bar_controller#foo_action'
Run Code Online (Sandbox Code Playgroud)

因此,默认情况下,引擎路由将在应用程序之后加载.这意味着由于我的应用程序中的全部路径,引擎路由无法访问.如何强制引擎路由首先(或最后)加载?

sko*_*rks 29

你要做的事情有点困难.如前所述,在应用程序路由之后加载引擎路由并且覆盖此行为可能会有问题.我可以想到你可以尝试的几件事.

路由路径初始化程序后使用初始化程序

engine.rb在rails源中有一个初始化器,实现你想要的一种方法是尝试挂钩它处理的功能.初始化程序默认情况下如下所示:

initializer :add_routing_paths do |app|
  paths.config.routes.to_a.each do |route|
    app.routes_reloader.paths.unshift(route) if File.exists?(route)
  end
end
Run Code Online (Sandbox Code Playgroud)

本质上,这应该采用Rails知道的所有路径文件的路径,并尝试将它们添加到路由重新加载器(如果它被更改,则自动为您重新路由您的路由文件).您可以定义另一个在此之后执行的初始化程序,然后您将检查路由重新加载器中存储的路径,拉出属于您的引擎的路径,将其从路径数组中删除并将其插回,但最后路径数组.所以,在你的config/application.rb:

class Application < Rails::Application
  initializer :munge_routing_paths, :after => :add_routing_paths do |app|
    engine_routes_path = app.routes_reloader.paths.select{|path| path =~ /<regex that matches path to my engine>/}.first
    app.routes_reloader.paths.delete(engine_routes_path)
    app.routes_reloader.paths << engine_routes_path
  end
end
Run Code Online (Sandbox Code Playgroud)

这可能会或可能不会工作,无论是我不推荐它,它不是特别优雅(即丑陋的黑客玩铁轨的胆量).

使用Rails 3.1

这可能不是一个选择,但如果是,我可能会选择这个.在Rails 3.1中,您可以拥有2种不同类型的引擎,完整且可安装(这是一个SO问题,讨论一些差异).但实质上你会将你的引擎改为可安装的引擎,可安装引擎中的路由是命名空间的,你可以明确地将它们包含在主应用程序的routes文件中,例如:

Rails.application.routes.draw do
  mount MyEngine::Engine => "/news"
end
Run Code Online (Sandbox Code Playgroud)

您还可以确定已安装的引擎路由的范围,并执行各种其他奇特的路由(此处有更多信息).长话短说,如果你可以去3.1然后这是使用的方法.

动态地将引擎中的路由插入到主应用程序中

目前最着名的Rails引擎之一是Devise.现在,设计是一个可能会为您的应用添加相当多路由的引擎,但如果你看一下设计源,你会发现它实际上根本没有config/routes.rb文件!这是因为设计动态地将其路由优势添加到主应用程序的routes.rb文件中.

当您运行带有设计的模型生成器时,生成器将执行的操作之一是在行devise_for :model后面添加一行,例如routes.rb文件的顶部Rails.application.routes.draw do.因此,在执行生成器以创建用户模型后,您的route.rb看起来与此类似:

Rails.application.routes.draw do
  devise_for :users
  ...
end
Run Code Online (Sandbox Code Playgroud)

现在,devise_for是一个神奇的方法,作为设计(in lib/devise/rails/routes.rb)的一部分,但实质上它将根据您生成的模型创建一堆我们都知道的常规路径.

我们需要知道的是,如何在应用程序routes.rb文件中插入此行,然后我们可以在我们的引擎中编写一个生成器,它将在主应用程序routes.rb文件的顶部插入我们的任何路由.为此,我们来看看lib/generators/devise/devise_generator.rb.在add_devise_routes方法中,最后一行是route devise_route.Route是一个Thor动作,它将传递给它的字符串插入到主应用程序的routes.rb文件中.所以我们可以编写自己的生成器并执行类似的操作,例如:

class MyCrazyGenerator < Rails::Generators::NamedBase
  ...
  def add_my_crazy_routes
    my_route  = "match '/news', :to => 'bar_controller#foo_action'"
    route my_route
  end
end
Run Code Online (Sandbox Code Playgroud)

当然,你需要确保所有的发电机基础设施到位,但这是它的本质.Devise是由一些非常聪明的铁杆家伙编写的,并且被很多人使用,仿效他们所做的可能是一个很好的方式.在我建议的3件事中,我会处理你的问题(考虑到转向rails 3.1可能不是一个选项).