命名空间在`app`目录中

时间:2017-01-05 12:56:52

标签: ruby-on-rails ruby ruby-on-rails-5 autoload

在我们的app目录中,我们希望某些子目录包含命名空间类,而某些子目录包含顶级类。例如:

  • app/models/user.rb定义::User
  • app/operations/foo.rb定义::Operations::Foo
  • app/operations/user/foo.rb定义::Operations::User::Foo

我们的application.rb包含以下配置:

config.paths = Rails::Paths::Root.new(Rails.root)
config.paths.add 'app/models', eager_load: true
config.paths.add 'app', eager_load: true

这在大多数情况下都可以正常工作,但有时候在开发模式下使用Rails'自动加载打开,这导致加载错误的类。例如,::User被误认为是Operations::User,反之亦然。

有没有办法配置此行为,以便它可以正常工作?

如果没有,我能想到的唯一解决方法是为" namespaced"创建第二个目录。类,与appapp_namespaced一致。或者app/namespaced,因为应用级代码应位于app内。但这对我来说似乎是丑陋的变通方法。

编辑:@dgilperez所要求的一个小例子:

# app/models/user.rb
class User
end

# app/models/group.rb
class Group
  def some_method
    # Since we're in a top-level namespace, User should always
    # resolve to ::User. But, depending on some seemingly random
    # factors, it sometimes resolves to Operations::User.
    User.new
  end
end

# app/operations.rb
module Operations
end

# app/operations/user/create.rb
module Operations::User
  class Create
    def some_method
      # Here, as expected, I need to prefix with "::" as
      # 'User' would refer to the module we're currently in.
      # That's fine and works.
      ::User.new
    end
  end
end

1 个答案:

答案 0 :(得分:0)

是的,这是rails自动加载的缺点。默认情况下,它会加载/app中的所有内容,但第一级目录结构不是名称的一部分。这样app/models/user.rb可以定义User,而不是Models::User

您无需弄乱加载路径。这里提供了几种方法/解决方法。

  1. 在我当前的项目中,我们只需将命名空间目录加倍。这意味着如果我们要定义ServiceObjects::User::Import,我们会将其放入app/service_objects/service_objects/user/import.rb

  2. 我个人更喜欢这种方法的变体,即将所有“非标准”内容放入app/lib(可以是app/custom或任何你想要的东西)。通过这种方式,目录名称没有奇怪的重复,所有自定义代码都包含在内。