Ruby 命名空间

Posted

技术标签:

【中文标题】Ruby 命名空间【英文标题】:Ruby namespacing 【发布时间】:2015-07-07 08:25:09 【问题描述】:

我是 ruby​​ 的新手,来自 php 背景,但我没有点击。

所以,假设我有一个 Ruby on Rails 应用程序,并且我正在像这样对我的 API 进行版本控制:

app
|_controllers
  |_api
  | |_v1
  | | |_application_controller.rb
  | | |_user_controller.rb
  | |_application_controller.rb
  |_application_controller.rb

同类结构同

# Versioned API V1 app controller
module Api
  module V1
    class ApplicationController
    end
  end
end

# Versioned API app controller
module Api
  class ApplicationController
  end
end

# Root app controller
class ApplicationController
end

#The code in question
module Api
  module V1
    class UserController < ApplicationController
    end
  end
end

所以问题是,ruby 是否会寻找 Api::V1::ApplicationControllerApi::ApplicationControllerApllicationController 来进行扩展?

除非我指定Api::ApplicationController,否则&lt; ApplicationController 是否会查找它自己的命名空间?如果是这样,我如何指定根?

【问题讨论】:

【参考方案1】:

当你使用

#The code in question
module Api
  module V1
    class UserController < ApplicationController
    end
  end
end

ApplicationControllerdefinition 将在 Api::V1 中搜索,如果在 Api 中未找到,则在根命名空间中未找到。

我同意这可能会造成混淆,这就是我倾向于使用绝对路径的原因:::ApplicationController

如果我需要Api::ApplicationController,我会写::Api::ApplicationController

基本上,:: 告诉 ruby​​ 从根命名空间开始,而不是从代码所在的位置开始。


旁注

请注意,Rails 开发模式中存在恶性案例。为了获得速度,加载了严格的最小值。然后 Rails 在需要时查找类定义。

但这有时会失败的大例子,当你说::User已经加载,然后寻找::Admin::User。 Rails 不会寻找它,它会认为 ::User 可以解决问题。

这可以在您的代码中使用require_dependency 语句来解决。速度是有代价的:)

【讨论】:

cool :) 最令人困惑的是当您遇到像我的旁注中描述的问题时 有趣,我认为你的旁注解决了我遇到的问题here @dax 读起来很酷 :) 由于这种延迟加载,我经历了很多啊哈和错误的时刻【参考方案2】:

我宁愿建议不要在命名空间中写ApplicationController,我建议遵循以下

注意:如果您正在构建专业 api,最好让 Api::V1::BaseController 继承自 ActionController::Base,尽管我正在为您的具体情况提供解决方案

参考这篇文章:Implementing Rails APIs like a professional

1) 在 app/controllers/application_controller.rb 中以通常的方式定义应用控制器为

class ApplicationController < ActionController::Base
end 

2) 在 app/controllers/api/v1/base_controller.rb 中定义基本 api 控制器,即 Api::V1::BaseController,它将继承自 ApplicationController(您的情况),如

class Api::V1::BaseController < ApplicationController
end 

3) 在 app/controllers/api/v1/users_controller.rb 中定义您的 api 控制器,如 Api::V1::UsersController,它将继承自 Api::V1::BaseController

class Api::V1::UsersController < Api::V1::BaseController
end 

4) 添加所有后续控制器,例如Api::V1::UsersController(步骤 3)

那么路由会在config/routes.rb中包含命名空间路由

namespace :api do
  namespace :v1 do
    resources :users do 
      #user routes goes here 
    end
    # any new resource routing goes here 
    # resources :new_resource do 
    # end
  end
end

【讨论】:

尽管这并没有直接回答我的问题,但它为我提供了更广泛的 API 选择设计。谢谢。【参考方案3】:

您应该查看指南以了解路由: http://guides.rubyonrails.org/routing.html#controller-namespaces-and-routing

我认为这个问题非常类似于:

Rails Controller Namespace

作为短缺:

Rails 将通过文件夹自动检测命名空间。所以你不需要将它附加到名称中:

这篇博文解释得很好:

http://blog.makandra.com/2014/12/organizing-large-rails-projects-with-namespaces/

假设我们有一个 Invoice 类,每张发票可以有多个 发票项目:

class Invoice < ActiveRecord::Base
  has_many :items
end

class Item < ActiveRecord::Base
  belongs_to :invoice
end

显然发票是物品的组合,物品不能生存 没有包含发票。其他课程可能会 与 Invoice 而不是 Item 交互。所以让我们把 Item 从 通过将其嵌套到 Invoice 命名空间中。这涉及重命名 类到 Invoice::Item 并将源文件移动到 app/models/invoice/item.rb:

 class Invoice::Item < ActiveRecord::Base
   belongs_to :invoice
 end

同样适用于控制器和视图。

【讨论】:

以上是关于Ruby 命名空间的主要内容,如果未能解决你的问题,请参考以下文章

ruby 从命名空间#ruby #autoload自动加载一个类

ruby 具有命名空间的资源

ruby 加载命名空间目录中的所有模块

ruby Redis使用给定的命名空间过期密钥

使用 "::" 而不是 "module ..." 进行 Ruby 命名空间

如何在 Ruby 类/模块命名空间中翻译模型?