Rails 3.1: mecanismo x aplicativo montável

120

Alguém pode me ajudar a entender as diferenças entre um mecanismo Rails e um aplicativo montável? No Rails 3.1, você pode criar qualquer um com o comando "rails new plugin _ __ ".

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

Quando você gostaria de usar um contra o outro? Eu sei que você pode empacotar um mecanismo como uma jóia, por exemplo. Não é esse o caso dos aplicativos montáveis? Que outras diferenças existem?

Jeremy Raines
fonte

Respostas:

143

Eu notei o seguinte:

Motor completo

Com um mecanismo completo, o aplicativo pai herda as rotas do mecanismo. Não é necessário especificar nada parent_app/config/routes.rb. A especificação da gema no Gemfile é suficiente para o aplicativo pai herdar os modelos, rotas etc. As rotas do mecanismo são especificadas como:

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

Nenhum espaço para nome de modelos, controladores, etc. Estes são imediatamente acessíveis ao aplicativo pai.

Motor Montável

O espaço para nome do mecanismo é isolado por padrão:

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

Com um mecanismo montável, as rotas têm espaço para nome e o aplicativo pai pode agrupar essa funcionalidade em uma única rota:

# 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 

Modelos, controladores etc. são isolados do aplicativo pai - embora os auxiliares possam ser compartilhados facilmente.

Essas são as principais diferenças que vi. Talvez haja outros? Eu perguntei aqui , mas ainda não recebi uma resposta.

Minha impressão é que, como um mecanismo completo não se isola do aplicativo pai, ele é melhor usado como um aplicativo autônomo adjacente ao aplicativo pai. Eu acredito que conflitos de nomes podem ocorrer.

Um mecanismo montável pode ser usado em situações nas quais você deseja evitar conflitos de nome e agrupar o mecanismo em uma rota específica no aplicativo pai. Por exemplo, estou trabalhando na construção do meu primeiro mecanismo projetado para atendimento ao cliente. O aplicativo pai pode agrupar sua funcionalidade em uma única rota, como:

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

Se eu estiver muito longe de minhas suposições, alguém por favor me avise e eu corrigirei esta resposta. Eu fiz um pequeno artigo sobre o assunto aqui Cheers!

astjohn
fonte
1
Um mecanismo montável pode ser roteado / montado na raiz do aplicativo pai?
Slick23
3
@ JustinM você poderia tentar mount MyEngine::Engine => "/". Funciona com recursos, talvez também seja o caso de motores.
Benoit Garret
2
@astjohn Grande resumo de seus blogs. Mas não seria o contrário? Um mecanismo completo seria "incompleto" e precisaria que o aplicativo pai funcionasse, enquanto o mecanismo montável pode funcionar de forma independente, pois é "isolado" do aplicativo pai?
Theo Scholiadis 5/06
39

Ambas as opções irão gerar um mecanismo . A diferença é que --mountablecriará o mecanismo em um espaço para nome isolado, enquanto --fullcriará um mecanismo que compartilhará o espaço para nome do aplicativo principal.

As diferenças serão manifestadas de três maneiras:

1) O arquivo de classe do mecanismo chamará 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) O config/routes.rbarquivo do mecanismo terá espaço para nome:

Motor completo:

Rails.application.routes.draw do
end

Motor montado:

MyMountableEngine::Engine.routes.draw do
end

3) A estrutura do arquivo para controladores, auxiliares, visualizações e ativos terá espaço para nome:

criar app / controllers / my_mountable_engine /application_controller.rb
criar app / helpers / my_mountable_engine /application_helper.rb
criar app / mailers criar app / modelos
criar app / views / layouts / my_mountable_engine /application.html.erb
criar app / assets / images / my_mountable_engine
crie app / assets / stylesheets / my_mountable_engine /application.css
crie app / assets / javascripts / my_mountable_engine /application.js
crie config / routes.rb crie lib / my_mountable_engine.rb
crie lib / tasks / my_mountable_engine.rake
crie lib / my_mountable_engine.rake .rb
crie lib / my_mountable_engine / engine.rb


Explicação

O caso de uso da --fullopção parece ser muito limitado. Pessoalmente, não consigo pensar em nenhuma boa razão para que você queira separar seu código em um mecanismo sem isolar o espaço para nome - essencialmente, apenas forneceria dois aplicativos fortemente acoplados que compartilham estruturas de arquivos idênticas e todos os conflitos e vazamentos de código isso implica.

Todas as documentações que eu vi demonstram a --mountableopção e, de fato, o guia de borda atual o encoraja fortemente a incluir isolate namespace- o mesmo que dizer --mountablesobre o uso --full.

Finalmente, há uma confusão de terminologia: Infelizmente, rails plugin -hmostra as seguintes descrições:

[--full] # Gere um mecanismo Rails com o aplicativo Rails incluído para teste
[--mountable] # Gere aplicativos isolados montáveis

Isso dá a impressão de que você usa --fullpara criar um "mecanismo" e --mountablecriar outra coisa chamada "aplicativo montável", quando na verdade eles são os dois mecanismos - um com espaço para nome e outro não. Isso pode gerar confusão, já que os usuários que desejam criar um mecanismo provavelmente assumirão que essa --fullé a opção mais relevante.

Conclusão

  • rails plugin new something --full= Engine no espaço de nome do seu aplicativo. (Por que você?)
  • rails plugin new something --mountable= Mecanismo com seu próprio espaço para nome. (Impressionante)

Referências

Yarin
fonte
9
Há uma boa razão para usar --full: se você tem partes de um site de rails, deseja manter-se integrado (não em um espaço de nome isolado) e ainda compartilhar entre diferentes projetos de rails. Também pode ser mais simples do que isso: talvez sua gema não adicione muito, mas você deseja conectá-la corretamente.
Nathanvda
2
@nathanvda - Certo, mas eu acho que se você está compartilhando algo em vários projetos que realmente deve ser namespaced, porque você está usando basicamente como um plugin
Yarin
Eu acho que você pode querer usar --full se você quiser isolar seus arquivos, namespace seus sites de chamada para quando você fizer, Admin::AdminService.some_actionmas não precisar alterar suas rotas, se outros aplicativos do lado do cliente, como um aplicativo Ember, usarem as rotas relacionadas ao código que você usa. quer isolar. --full parece ser um passo intermediário que pode ser mais fácil de implementar.
precisa saber é o seguinte
Atualmente, estou trabalhando em um aplicativo internacional que precisa lidar com regulamentos específicos de cada país, mas ainda expõe a mesma interface para o mundo. Eu tenho uma instância de "Core" por país, sem necessidade de lidar com tudo de uma vez. Os "motores do país" não fazem sentido sozinhos; portanto, o acoplamento ao aplicativo "principal" não é um problema. No entanto, não quero que eles estejam em seu próprio espaço para nome, porque o aplicativo principal não deve saber em que país opera. Eu sinto que um mecanismo "completo" é mais como organizar seus arquivos e classes de maneira modular, mas ainda mantendo seu "monólito" no lugar.
Mankalas
17

Eu estava pensando o mesmo e, portanto, acabou aqui. parece-me que as respostas anteriores abrangem basicamente a pergunta, mas achei que o seguinte também poderia ajudar:

# 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

de particular interesse (para mim) é o fato de que não há diferença entre

rails plugin new test-plugin -T --mountable

e

rails plugin new test-plugin -T --full --mountable
Corey Innis
fonte
Talvez seja porque --fulltem precedência --mountable?
Mankalas
8

Meu entendimento da diferença é que os mecanismos são como plugins e adicionam funcionalidade aos aplicativos existentes. Embora os aplicativos montáveis ​​sejam essencialmente um aplicativo e possam ser independentes.

Portanto, se você quiser executá-lo sozinho ou em outro aplicativo, você criaria um aplicativo montável. Se você pretende que seja uma adição aos aplicativos existentes, mas não é executado por si só, você o tornaria um mecanismo.

JDutil
fonte
2

A diferença, acredito, é que os aplicativos montáveis ​​são isolados do aplicativo host, portanto, eles não podem compartilhar classes - modelos, auxiliar etc. Isso ocorre porque um aplicativo Montável é um terminal de Rack (por exemplo, um aplicativo Rack por si só) )

Isenção de responsabilidade: Eu, como a maioria, apenas comecei a brincar com o Rails 3.1.

Kris
fonte
Acordado. Uma coisa que parece estranha é que, por padrão, um mecanismo fornece uma pasta "modelos", mas um aplicativo montável não. Pergunto-me se o "melhor prática" seria ter geradores que criam modelos para o aplicativo, incluindo, uma vez que parece que você não gostaria de ter nenhum migrações no motor / moutable
Jeremy Raines