Rails 3.1:引擎与可安装的应用程序


120

有人可以帮助我了解Rails Engine和可安装应用之间的区别吗?在Rails 3.1中,您可以使用“ rails new plugin _ __ ”命令创建一个。

rails plugin new forum --full        # Engine
rails plugin new forum --mountable   # Mountable App

您什么时候要使用一个相对于另一个?我知道您可以将Engine打包为gem。可挂载应用程序不是这种情况吗?还有什么其他区别?

Answers:


143

我注意到以下几点:

全引擎

使用完整的引擎,父应用程序将从引擎继承路由。没有必要在parent_app/config/routes.rb。在Gemfile中指定gem足以使父应用程序继承模型,路线等。引擎路线指定为:

# my_engine/config/routes.rb 
Rails.application.routes.draw do 
  # whatever 
end 

没有模型,控制器等的命名空间。父应用程序可以立即访问它们。

可安装引擎

默认情况下,引擎的名称空间是隔离的:

# my_engine/lib/my_engine/engine.rb
module MyEngine 
  class Engine < Rails::Engine 
    isolate_namespace MyEngine 
  end 
end

使用可安装的引擎时,路由将被命名为名称空间,并且父应用程序可以在单个路由下捆绑此功能:

# my_engine/config/routes.rb 
MyEngine::Engine.routes.draw do 
  #whatever 
end 

# parent_app/config/routes.rb 
ParentApp::Application.routes.draw do 
    mount MyEngine::Engine => "/engine", :as => "namespaced" 
end 

模型,控制器等与父应用程序隔离-尽管可以轻松共享助手。

这些是我发现的主要区别。也许还有其他?我问过这里,但尚未收到回复。

我的印象是,由于完整引擎不会将自身与父应用程序隔离,因此最好将其用作与父应用程序相邻的独立应用程序。我相信名称冲突可能会发生。

在您要避免名称冲突并将引擎捆绑在父应用程序中的特定路径下的情况下,可以使用可安装的引擎。例如,我正在构建我的第一个为客户服务设计的引擎。父应用程序可以在一条路径上捆绑其功能,例如:

mount Cornerstone::Engine => "/cornerstone", :as => "help" 

如果我的假设与您相去甚远,请告诉我,我将解决此问题。我在这里 干了一篇关于这个主题的小文章!


1
可以在父应用程序的根目录下路由/安装可安装引擎吗?
Slick23 2011年

3
@JustinM您可以尝试mount MyEngine::Engine => "/"。它适用于资源,也许引擎也适用。
Benoit Garret

2
@astjohn您的博客的总结。但这不是相反吗?完整引擎是否“不完整”并且需要父应用程序才能工作,而可挂载引擎却可以独立运行,因为它与父应用程序“隔离”了吗?
Theo Scholiadis 2012年

39

这两个选项都会生成一个引擎。不同之处在于,--mountable它将在隔离的名称空间中--full创建引擎,而将创建共享主应用程序名称空间的引擎。

差异将通过3种方式体现出来:

1)引擎类文件将调用isolate_namespace

lib / my_full_engine / engine.rb:

module MyFullEngine
  class Engine < Rails::Engine
  end
end

lib / my_mountable_engine / engine.rb:

module MyMountableEngine
  class Engine < Rails::Engine
    isolate_namespace MyMountableEngine # --mountable option inserted this line
  end
end

2)引擎的config/routes.rb文件将被命名为:

全引擎:

Rails.application.routes.draw do
end

发动机:

MyMountableEngine::Engine.routes.draw do
end

3)控制器,助手,视图和资产的文件结构将被命名为:

创建app / controllers / my_mountable_engine /application_controller.rb
创建app / helpers / my_mountable_engine /application_helper.rb
创建app / mailers创建app /模型
创建app / views / layouts / my_mountable_engine /application.html.erb
创建app / assets / images / my_mountable_engine
创建app / assets / stylesheets / my_mountable_engine /application.css
创建app / assets / javascripts / my_mountable_engine /application.js
创建config / routes.rb创建lib / my_mountable_engine.rb
创建lib / tasks / my_mountable_engine.rake 创建lib / my_mountable_engine / engine .rb
创建lib / my_mountable_engine / version .rb


说明

--full选项的用例似乎非常有限。就我个人而言,我想不出为什么要在不隔离名称空间的情况下将代码分离到引擎中的任何好理由-从本质上来说,这只是给您两个紧密耦合的应用程序,它们共享相同的文件结构以及所有冲突和代码泄漏这需要。

我看过的每篇文档都演示了该--mountable选项,实际上,当前的边缘指南强烈建议您加入isolate namespace-就像说使用--mountableover一样--full

最后,术语混淆:不幸地rails plugin -h显示了以下描述:

[--full]#生成捆绑了Rails应用程序的Rails 引擎以进行测试
[--mountable]#生成可安装的隔离应用程序

这给人的印象是,您实际上--full用来创建“引擎”和--mountable创建其他东西(称为“可安装的应用程序”),而实际上它们都是引擎-一个命名空间而不是一个命名空间。这势必会引起混乱,因为希望创建引擎的用户可能会认为这--full是更相关的选项。

结论

  • rails plugin new something --full=应用程序名称空间中的引擎。(为什么?)
  • rails plugin new something --mountable=具有它自己的名称空间的引擎。(真棒)

参考资料


9
有一个很好的使用理由--full:如果您拥有Rails网站的一部分,则希望保持集成(而不是在隔离的命名空间中),并且仍要在不同的Rails项目之间共享。它也可以比这更简单:也许您的gem没有添加那么多,但是您希望能够正确地将其连接。
nathanvda

2
@nathanvda-是的,但是我想如果您要在多个项目中共享某些内容,则实际上应该为其命名空间,因为您基本上是将其用作插件
Yarin 2014年

我想如果您想隔离文件,为呼叫站点命名空间时可以使用--full,Admin::AdminService.some_action但如果其他客户端应用程序(例如Ember应用程序)使用与您的代码相关的路由,则不必更改路由想隔离。--full似乎是一个中间步骤,可能更容易实现。
Jwan622 '16

我目前正在开发一个国际应用程序,该应用程序需要处理特定于国家/地区的法规,但是却向世界展示了相同的界面。每个国家/地区只有一个“核心”实例,无需一次处理所有实例。“国家/地区引擎”本身没有意义,因此与“核心”应用程序的结合不是问题。但是,我不希望它们位于自己的名称空间中,因为核心应用程序必须不知道它在哪个国家/地区运营。我觉得“完整”引擎更像是以模块化方式组织文件和类的,但是仍然保持“整体”。
Mankalas

17

我在想同样的事情,因此就到这里了。在我看来,以前的答案基本上涵盖了这个问题,但我认为以下内容可能也会有所帮助:

# generate plugins (NOTE: using same name each time to minimize differences)
# -----------------------------------------------------------------------------

$ rails plugin new test-plugin -T
$ mv test-plugin{,.01}

$ rails plugin new test-plugin -T --mountable
$ mv test-plugin{,.02}

$ rails plugin new test-plugin -T --full
$ mv test-plugin{,.03}

$ rails plugin new test-plugin -T --full --mountable
$ mv test-plugin{,.04}




# compare "stock" (01) with "mountable" (02)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.01 test-plugin.02

Only in test-plugin.02: app
Only in test-plugin.02: config
Only in test-plugin.02/lib/test-plugin: engine.rb
diff -r test-plugin.01/lib/test-plugin.rb test-plugin.02/lib/test-plugin.rb
0a1,2
> require "test-plugin/engine"
> 
Only in test-plugin.02: script
diff -r test-plugin.01/test-plugin.gemspec test-plugin.02/test-plugin.gemspec
18a19
>   # s.add_dependency "jquery-rails"




# compare "stock" (01) with "full" (03)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.01 test-plugin.03
Only in test-plugin.03: app
Only in test-plugin.03: config
Only in test-plugin.03/lib/test-plugin: engine.rb
diff -r test-plugin.01/lib/test-plugin.rb test-plugin.03/lib/test-plugin.rb
0a1,2
> require "test-plugin/engine"
> 
Only in test-plugin.03: script
diff -r test-plugin.01/test-plugin.gemspec test-plugin.03/test-plugin.gemspec
18a19
>   # s.add_dependency "jquery-rails"




# compare "mountable" (02) with "full" (03)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.02 test-plugin.03

Only in test-plugin.03/app/assets/javascripts/test-plugin: .gitkeep
Only in test-plugin.02/app/assets/javascripts/test-plugin: application.js
Only in test-plugin.03/app/assets/stylesheets/test-plugin: .gitkeep
Only in test-plugin.02/app/assets/stylesheets/test-plugin: application.css
Only in test-plugin.03/app/controllers: .gitkeep
Only in test-plugin.02/app/controllers: test-plugin
Only in test-plugin.03/app/helpers: .gitkeep
Only in test-plugin.02/app/helpers: test-plugin
Only in test-plugin.03/app/mailers: .gitkeep
Only in test-plugin.03/app/models: .gitkeep
Only in test-plugin.03/app/views: .gitkeep
Only in test-plugin.02/app/views: layouts
diff -r test-plugin.02/config/routes.rb test-plugin.03/config/routes.rb
1c1
< TestPlugin::Engine.routes.draw do
---
> Rails.application.routes.draw do
diff -r test-plugin.02/lib/test-plugin/engine.rb test-plugin.03/lib/test-plugin/engine.rb
3d2
<     isolate_namespace TestPlugin




# compare "mountable" (02) with "full & mountable" (04)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.02 test-plugin.04

<no difference>




# compare "full" (03) with "full & mountable" (04)
# -----------------------------------------------------------------------------

$ diff -r test-plugin.03 test-plugin.04

Only in test-plugin.03/app/assets/javascripts/test-plugin: .gitkeep
Only in test-plugin.04/app/assets/javascripts/test-plugin: application.js
Only in test-plugin.03/app/assets/stylesheets/test-plugin: .gitkeep
Only in test-plugin.04/app/assets/stylesheets/test-plugin: application.css
Only in test-plugin.03/app/controllers: .gitkeep
Only in test-plugin.04/app/controllers: test-plugin
Only in test-plugin.03/app/helpers: .gitkeep
Only in test-plugin.04/app/helpers: test-plugin
Only in test-plugin.03/app/mailers: .gitkeep
Only in test-plugin.03/app/models: .gitkeep
Only in test-plugin.03/app/views: .gitkeep
Only in test-plugin.04/app/views: layouts
diff -r test-plugin.03/config/routes.rb test-plugin.04/config/routes.rb
1c1
< Rails.application.routes.draw do
---
> TestPlugin::Engine.routes.draw do
diff -r test-plugin.03/lib/test-plugin/engine.rb test-plugin.04/lib/test-plugin/engine.rb
2a3
>     isolate_namespace TestPlugin

(对我而言)特别有趣的是,

rails plugin new test-plugin -T --mountable

rails plugin new test-plugin -T --full --mountable

也许那是因为--full优先于--mountable
Mankalas

8

我对差异的理解是,引擎就像插件一样,为现有应用程序添加功能。尽管可挂载应用程序本质上是一个应用程序,并且可以独立运行。

因此,如果您希望能够单独运行它或在另一个应用程序中运行它,则可以制作一个可挂载的应用程序。如果您打算将它添加到现有应用程序中,但又不想单独运行,则可以使其成为引擎。


2

我认为,区别在于可挂载应用程序与主机应用程序是隔离的,因此它们无法共享类(模型,助手等)。这是因为可挂载应用程序是Rack端点(即,Rack应用程序本身就是)。

免责声明:与大多数人一样,我只是刚刚开始使用Rails 3.1。


同意 一件奇怪的事是,默认情况下,引擎为您提供了一个“模型”文件夹,而可安装的应用程序则没有。我想知道“最佳实践”是否是让生成器为包含应用创建模型的生成器,因为似乎您不想在引擎/可变组件中进行任何迁移
Jeremy Raines
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.