【问题标题】:How to define a nested controller to work with Rails autoloader?如何定义嵌套控制器以使用 Rails 自动加载器?
【发布时间】:2019-11-07 21:37:24
【问题描述】:

假设我有两个标准的 Rails 资源定义为控制器,每个都有自己的 CRUD 操作(indexshow 等...)

  • EmployeesController
  • Employees::AssignmentController

目录看起来像 -

app/
  controllers/
    - employees_controller.rb
    employees/
      - assignment_controller.rb

我正在尝试找出如何最好地定义第二个嵌套控制器以使用 Rails 自动加载器。

选项 A - 命名空间常量

如果我这样做-

class Employees::AssignmentController < ApplicationController
  ...
end

我在应用日志中和运行集成测试时收到以下错误:

LoadError: Unable to autoload constant Employees::AssignmentController, expected /Users/jeeves/git/my-project/app/controllers/employees/assignment_controller.rb to define it>

它不喜欢定义为单个命名空间的常量 - Employees::AssignmentController

选项 B - 模块内的嵌套常量

如果我这样做 -

module Employees
  class AssignmentController < ApplicationController
  end
end

我实际上得到了与上面相同的LoadError 错误。

选项 C - 类中的嵌套常量

最后,如果我这样做 -

class Employees
  class AssignmentController < ApplicationController
  end
end

我得到TypeError: Employees is not a class,这是有道理的,因为外部class 没有定义。我尝试通过添加带有空文件的显式 class 定义来修复它

 app/
   controllers/
     - employees_controller.rb
+    - employees.rb
     employees/
       - assignment_controller.rb
class Employees
end

这很有效。但是在app/controllers 中保留这个额外的虚拟文件感觉很愚蠢,尤其是当它甚至不是控制器本身时。

问题

有没有正确的方法来处理上述情况?选项 C 是我唯一的选择吗?我是否正确使用了命名空间,还是应该一起避免它们?

谢谢!

【问题讨论】:

  • 这里要注意的一点是,您使用的是单数 AssignmentController,如果您声明的是单数资源,这很好,但如果用户可以有很多任务并且您使用的是 @987654339,则不行@.

标签: ruby-on-rails constants autoload


【解决方案1】:

使用显式定义(并重新打开)命名空间的类和模块 嵌套。使用范围解析运算符可能会导致令人惊讶的 由于 Ruby 的词法作用域,不断查找,这取决于 在定义点嵌套模块。
- The Ruby Style Guide

这种令人惊讶的行为的一个例子是:

class Employees::AssignmentController
  def index
    @rate = Rate.find(...)
  end
end

您希望 Rate 被解析为 Employees::Rate,但实际上它被解析为 ::Rate,因为词法范围是 ::

这是首选方法:

module Employees
  class AssignmentController
    def index
      @rate = Rate.find(...) # resolves to Employees::Rate
    end
  end
end

它重新打开模块并在正确的词法范围内定义一个新常量。

至于替代 C - 它是可能的,因为 Ruby 中的类是模块(如果你不相信我,请查看 Class.ancestors)但它不被认为是好的形式,因为类应该是可以实例化的东西。

rails 生成器通过使用范围解析运算符以“错误”的方式执行此操作,但这实际上只是由于文件模板系统的限制。

那为什么会出现加载错误?

我其实不知道。这是首选方法,并且没有明显的原因为什么它在这种情况下不起作用。仔细检查一切。通过运行spring stop 重新启动 spring 并重新启动服务器。

【讨论】:

    猜你喜欢
    • 2012-07-01
    • 2012-08-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-03-17
    • 2012-07-31
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多