17

我想在 rails 4 应用程序中拆分我的路线。对于 rails 3,这个问题已经回答了几次,例如:

在 rails 4 + 如何控制路线加载顺序的正确方法是什么?

从rails 3个问题建议:

应用程序.rb

    config.paths['config/routes'] = Dir["config/routes/*.rb"]

失败:

/Users/jordan/.rvm/gems/ruby-2.0.0-head@books/gems/railties-4.0.0/lib/rails/application/routes_reloader.rb:10:in `rescue in execute_if_updated': Rails:: Application::RoutesReloader#execute_if_updated 委托给 updater.execute_if_updated,但 updater 为 nil:

@route_sets=[#]> (运行时错误)

4

4 回答 4

21

我是这样管理的:

# config/application.rb
config.autoload_paths << Rails.root.join('config/routes')

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

  extend ApiRoutes
end

# config/routes/api_routes.rb
module ApiRoutes
  def self.extended(router)
    router.instance_exec do
      namespace :api do
        resources :tasks, only: [:index, :show]
      end
    end
  end
end

在这里,我将config/routes目录添加到其中定义的自动加载模块。这将确保在这些文件更改时重新加载路由。

用于extend将这些模块包含到主文件中(它们将被自动加载,不需要它们)。

使用instance_execinsideself.extended在路由器的上下文中绘制路由。

于 2016-01-14T19:34:25.057 回答
9

聚会有点晚了,但是您可以在 Rails 4 中通过猴子修补您的 routes.rb 文件顶部的映射器来做到这一点。IE:

# config/routes.rb
class ActionDispatch::Routing::Mapper
  def draw(routes_name)
    instance_eval(File.read(Rails.root.join("config/routes/#{routes_name}.rb")))
  end
end

然后使用drawroutes.rb 中的方法:

Rails.application.routes.draw do
  draw :api
end

这将需要 config/routes/api.rb 中的文件。

一个稍微完整的解释,这里有拆分路由文件的例子

于 2015-04-28T06:10:31.587 回答
4

这已于 2012 年 6 月从 Rails 4 中删除。5e7d6bba恢复了较早的提交,删除了对加载多个外部路由文件作为 config.rb 的一部分的支持。

如需进一步阅读,请查看有关此提交的评论。

于 2013-09-19T03:09:01.453 回答
1

I don't like previously posted solutions - extensions through monkey-patching aside - since they either:

  1. break OOP (File.read + instance_eval - cripes) or
  2. inhibit reusability: including modules - you can do it only once - never mind that on the 2nd you understand that module inclusion is actually a mechanic to execute a bit of code, cripes

we're not in the 2000s any more, it shouldn't be acceptable to move parts of source files around and File.read-instance_eval them and then wonder what happened - or include modules as a poor man's function call - if there's any alternative.

I do this, notice it is nestable:

scope :processing do
  SomeModule::SomeDomain::Routes.call(self)
end

# and it's reusable:
scope :some_other_scope do
  SomeModule::SomeDomain::Routes.call(self)
end

The benefit of this approach is that in the end it's just simple executable ruby code that can be moved around and understood clearly both by your IDE and by your fellow programmers.

You will find the above-mentioned piece of code in routes.rb you will look at it, you will control-click it and what you'll find is what you expected:

module SomeModule::SomeDomain
  class Routes
    def self.call r
      r.scope :some_scope do
        r.match .....
    end
  end
end

this means this is clean code.

It's also not stuck in "function-oriented code organization" that rails seemingly enforces for a long time now, but allows you to build domain-specific structures with their own route trees that should be the preferable norm.

PS

I also use a module that makes a class quack like a function - allows composition with procs and much more - but this isn't really necessary here, it'd just give you the syntax candy of saying SomeModule::SomeDomain::Routes[self]

于 2019-10-21T10:09:51.423 回答