9

我正在开发一个使用 Rails 引擎的 Ruby on Rails 3(.0) 应用程序。但是,在我的本地应用程序中,我想覆盖 Rails 引擎提供的路由之一。

从引擎配置/routes.rb:

match 'their_named_route' => 'controller#action', :as => 'the_route'

从我的应用程序配置/routes.rb:

match 'my_named_route' => 'controller#action', :as => 'the_route'

但是,当我检查路线时,两者似乎都处于活动状态(并且它们的路线似乎“获胜”,至少在引擎控制器内)

$ rake routes
the_route  /my_named_route(.:format)    {:controller=>"controller", :action=>"action"}
the_route  /their_named_route(.:format) {:controller=>"controller", :action=>"action"}

有没有一种好方法可以强制我的本地应用程序的命名路由优先?

4

7 回答 7

8

我通过将引擎的路由从 config/routes.rb 移动到引擎类本身的类方法来解决这个问题:

module MyEngine
  class Engine < Rails::Engine
    def self.routes
      MyRailsApp::Application.routes.draw do
        resources :products
      end
    end
  end
end

然后在基础应用程序的路由文件中:

MyRailsApp::Application.routes.draw do
  # Routes for base app including the ones overriding MyEngine::Engine.

  MyEngine::Engine.routes
end

然后我可以愉快地用引擎中的路由覆盖基础应用程序中的任何路由。

请注意,覆盖路由需要在覆盖路由之前定义,因为较早定义的路由优先于后面的路由。

于 2011-08-25T04:51:10.907 回答
6

恐怕没有这么简单的方法。路由在 中定义lib/action_dispatch/routing/mapper.rb:271,它调用 RouteSet 上的 add_route(在 中定义rack-mount-0.6.14/lib/rack/mount/route_set.rb,并在第 71 行附加了名称)。没有 remove_route 方法,Engine 的路由是最后添加的。您可以在使用 Rails.application.routes.draw 初始化应用程序后手动添加路由,而不是将其放在 routes.rb 中,或者您可以修补引擎。

于 2011-05-16T14:17:45.603 回答
4

无法覆盖引擎中的路由。相反,您必须定义一个否决路线。您可以通过调用prepend引擎的路由器来做到这一点:

An::Engine.routes.prepend do
  root :to => "somewhere#action"
end

如果引擎的命名空间是隔离的,这将使用SomewhereController引擎命名空间内的 from。如果没有,它将使用典型的SomewhereController.

如果要覆盖路由以返回 404,我能想到的最好方法是重定向到 404 页面:

match "/route_goes_here" => redirect("/404")
于 2013-02-19T21:26:39.217 回答
2

您需要将初始化程序挂钩添加到 config/application.rb,如下所示:

class Application < Rails::Application

  config.encoding = "utf-8"

  ...

  initializer :add_routing_paths do |app|
    their_routes_path = app.routes_reloader.paths.select{|path| path =~ /DIR/}.first
    app.routes_reloader.paths.delete(their_routes_path)
    app.routes_reloader.paths.unshift(their_routes_path)
  end
end

它首先加载你的引擎的 roues.rb,你可以覆盖他们的路线。

于 2011-05-17T08:48:56.630 回答
2

您可以按照上面 Ryan Bigg 的建议预先添加路线。我发现为了用我的自定义路由覆盖命名路由助手,我需要调用append而不是prepend,如下所示:

An::Engine.routes.append do
  root :to => "somewhere#action"
end

否则,应用程序包含两个路由,并且引擎路由器的命名助手是最后一个定义,因此是应用的那个。

于 2013-03-11T19:53:39.910 回答
1

routes.rb 中定义的路由规则自上而下应用,直到找到匹配项。只需将更高优先级的规则移动到安装引擎的行上方,我就可以覆盖已安装引擎中定义的路线。所以,

get 'about', controller: 'static', action: 'about', as: 'about'
mount My::Engine => '/'

导致应用程序将 /about/ 请求路由到(在这种情况下)静态控制器,而:

mount My::Engine => '/'
get 'about', controller: 'static', action: 'about', as: 'about'

导致应用程序将 /about/ 请求路由到已安装引擎中定义的路由。

于 2016-11-03T17:49:39.997 回答
0

要替换 gem 或引擎提供的默认路由路径,我们可以通过以下方式实现。对我来说,我想从所有路由 /user/ spree_user /sign_in 中将'spree_user' 替换为 'account' 等,我按以下方式执行此操作

步骤 1 创建 config/some_engine_route_override.rb
复制引擎路由文件的内容并根据需要更新路由

application.rb 中的第 2 步使用以下钩子

# Override Spree Core routes in order to translate products routes
initializer "delete_spree_core_routes", after: "add_routing_paths" do |app|
  new_spree_auth_route_path = File.expand_path('../../config/some_engine_route_override.rb', __FILE__)
  routes_paths = app.routes_reloader.paths

  spree_devise_auth_route_path = routes_paths.select{ |path| path.include?("spree_auth_devise") }.first

  if spree_devise_auth_route_path.present?
    spree_core_route_path_index = routes_paths.index(spree_devise_auth_route_path)

    routes_paths.delete_at(spree_core_route_path_index)
  
    routes_paths.insert(spree_core_route_path_index, new_spree_auth_route_path)
   
  end
end
于 2022-01-04T04:31:42.737 回答