我正在构建我的第一个Rails引擎。我称之为my_engine
,因此它会生成文件
lib/my_engine.rb
lib/my_engine/engine.rb
lib/my_engine/version.rb
所有人都有名为MyEngine
的模块。在gemspec中,gem名称也设置为my_engine
。
如果我创建了一个模型my_model
,它会进入app/models/my_engine/my_model.rb
,并生成为
module MyEngine
class MyModel < ActiveRecord::Base
end
end
如果我在这里创建一个类方法,并将gem放在一个Rails项目中,一切正常。
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!"
但是,我不希望宝石名称为my_engine
。但是,如果我将gemspec中的名称更改为其他内容,例如what-i-really-want-to-name-it
,则一切都会停止工作。 Rails看不到我的模型,虽然它可以看到我的命名空间。我确实在Rails应用程序中更改了gem名称并重新捆绑,因此它不是问题。
$ 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__'
为什么&#34;这个&#34;直接绑在宝石名字上?这有什么办法吗?我真的希望宝石名称和模块名称是不同的值。
使用:Rails 4.2.6,Ruby 2.3.0
答案 0 :(得分:3)
答案是Rails的基本概念之一是:
当您决定覆盖使用Configuration的约定原则时,这是一个Rails反模式。有可能做到这一点并且快乐并拥有一个有效的Rails应用程序吗?当然,但这不是您希望在Rails应用程序上显示的工作示例。
因此,惯例是模块名称与gem名称匹配。这只是一个惯例,但由于惯例是Rails城镇中相互商定的法律,所以当你不遵守它时,你就会反对模式。
已添加以回应OP评论
Rails引擎的典型特征是它们使用隔离的命名空间和隔离的资源。 Gems没有,所以实际上答案是肯定的,使用Rails引擎确实强制执行gem不存在的命名空间约定。并且中间件使用该命名空间来使main_app在运行时与引擎分离。两个例子来说明:
一个极端的例子:您可以将应用程序安装为引擎本身。命名空间将一个与另一个隔离,因此中间件服务作用于正确的进程,这些进程仅由命名空间 区分。
另一个例子:安装在main_app上的2个引擎。现在基本上有3个应用正在运行。在这种情况下,您希望如何实现非传统的命名空间隔离?
<强>因此... 强> 可以在Rails引擎中敲入不合格的命名空间吗?大概。我从来没有试过。 但是您的引擎无法移植。更糟糕的是,安装它的人将无法安装另一个符合要求的引擎(并共享main_app和中间件堆栈),因为你已经迫使它们进入破坏传统Rails引擎的配置迷宫。这最后部分是一个理论。