Why does a Rails engine's gem name have to “match” the module/namespace name?
我正在制造我的第一个Rails引擎。我称它为
1 2 3 | lib/my_engine.rb lib/my_engine/engine.rb lib/my_engine/version.rb |
全部都有名为
如果我创建模型
1 2 3 4 | module MyEngine class MyModel < ActiveRecord::Base end end |
如果我在此处创建一个类方法,并将gem放入Rails项目中,则一切正常。
1 2 3 4 5 6 7 | def self.hello "Hello from your Engine's model!" end $ bundle exec rails c [1] (pry) main: 0> MyEngine::MyModel.hello =>"Hello from your Engine's model!" |
但是,我不希望gem名称为
1 2 3 4 5 6 | $ bundle exec rails c [1] (pry) main: 0> MyEngine::VERSION =>"0.0.1" # default version from engine generation [2] (pry) main: 0> MyEngine::MyModel.hello NameError: uninitialized constant MyEngine::MyModel from (pry):2:in `__pry__' |
为什么" this"直接与ruby名称绑定?有什么解决方法吗?我真的很想让ruby名称和模块名称具有不同的值。
使用:Rails 4.2.6,Ruby 2.3.0
答案是Rails的基本概念之一是:
Convention over configuration.
当您决定使用配置替代约定的原则时,这就是Rails的反模式。是否有可能做到这一点并保持快乐并拥有可正常运行的Rails应用程序?可以,但这不是您要在Rails应用程序上进行工作的示例所示的代码。
因此,惯例是模块名称与gem名称匹配。这只是一个约定,但是由于约定是Rails镇达成的共同商定的法律,因此如果您不遵循约定,就会成为反模式。
为回应OP评论而添加
Rails引擎的典型特征是它们使用隔离的名称空间和隔离的资源。ruby没有,因此实际上答案是肯定的,使用Rails引擎会强制执行ruby不存在的命名空间约定。中间件使用该命名空间在运行时将main_app与引擎分离。两个例子来说明:
一个极端的例子:您可以将一个应用程序作为引擎安装在其自身上。命名空间将彼此隔离,因此中间件服务在正确的进程上起作用,这些进程仅由名称空间来区分。
另一个示例:main_app上安装了2个引擎。现在基本上有3个应用程序正在运行。在这种情况下,您将如何实现非常规名称空间隔离?
所以...
是否可以在Rails引擎中加入不一致的名称空间?大概。我从来没有试过。但是您的引擎将无法移植。更糟糕的是,安装它的人将无法安装其他符合标准的引擎(并共享main_app和中间件堆栈),因为您已将它们置于破坏常规Rails引擎的配置迷宫中。最后一部分是理论。