Rails 3.1: motor frente a aplicación montable

120

¿Alguien puede ayudarme a comprender las diferencias entre Rails Engine y una aplicación montable? En Rails 3.1, puede crear cualquiera con el comando "rails new plugin _ __ ".

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

¿Cuándo querría usar uno frente al otro? Sé que puedes empaquetar un motor como una joya, para uno. ¿No es ese el caso de las aplicaciones montables? ¿Qué otras diferencias existen?

Jeremy Raines
fuente

Respuestas:

143

He notado lo siguiente:

Motor completo

Con un motor completo, la aplicación principal hereda las rutas del motor. No es necesario especificar nada en parent_app/config/routes.rb. Especificar la gema en Gemfile es suficiente para que la aplicación principal herede los modelos, rutas, etc. Las rutas del motor se especifican como:

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

Sin espacio de nombres de modelos, controladores, etc. Estos son inmediatamente accesibles para la aplicación principal.

Motor montable

El espacio de nombres del motor está aislado de forma predeterminada:

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

Con un motor montable, las rutas tienen un espacio de nombres y la aplicación principal puede agrupar esta funcionalidad en una sola ruta:

# 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 

Los modelos, controladores, etc. están aislados de la aplicación principal, aunque los ayudantes se pueden compartir fácilmente.

Estas son las principales diferencias que he detectado. ¿Quizás hay otros? He preguntado aquí , pero aún no he recibido una respuesta.

Mi impresión es que, dado que un motor completo no se aísla de la aplicación principal, es mejor utilizarlo como una aplicación independiente adyacente a la aplicación principal. Creo que podrían producirse conflictos de nombres.

Se podría utilizar un motor montable en situaciones en las que desee evitar conflictos de nombres y agrupar el motor en una ruta específica en la aplicación principal. Por ejemplo, estoy trabajando en la construcción de mi primer motor diseñado para servicio al cliente. La aplicación principal podría agrupar su funcionalidad en una única ruta, como:

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

Si me equivoco en mis suposiciones, que alguien me lo haga saber y arreglaré esta respuesta. He hecho un pequeño artículo sobre el tema aquí ¡Saludos!

astjohn
fuente
1
¿Se puede enrutar / montar un motor montable en la raíz de la aplicación principal?
Slick23
3
@JustinM, podrías intentarlo mount MyEngine::Engine => "/". Funciona para los recursos, tal vez ese también sea el caso de los motores.
Benoit Garret
2
@astjohn Gran resumen de sus blogs. ¿Pero no sería al revés? ¿Un motor completo estaría "incompleto" y necesitaría la aplicación principal para funcionar, mientras que el motor montable puede funcionar de forma independiente, ya que está "aislado" de la aplicación principal?
Theo Scholiadis
39

Ambas opciones generarán un motor . La diferencia es que --mountablecreará el motor en un espacio de nombres aislado, mientras --fullque creará un motor que comparte el espacio de nombres de la aplicación principal.

Las diferencias se manifestarán de 3 formas:

1) El archivo de clase de motor llamará 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) El config/routes.rbarchivo del motor tendrá un espacio de nombres:

Motor completo:

Rails.application.routes.draw do
end

Motor montado:

MyMountableEngine::Engine.routes.draw do
end

3) La estructura de archivos para controladores, ayudantes, vistas y activos tendrá un espacio de nombres:

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


Explicación

El caso de uso de la --fullopción parece ser muy limitado. Personalmente, no puedo pensar en ninguna buena razón por la que desee separar su código en un motor sin aislar también el espacio de nombres. Básicamente, solo le brindaría dos aplicaciones estrechamente acopladas que comparten estructuras de archivos idénticas y todos los conflictos y fugas de código. eso implica.

Cada pieza de documentación que he visto demuestra la --mountableopción y, de hecho, la guía de borde actual le recomienda encarecidamente que la incluya isolate namespace, que es lo mismo que decir que se --mountableacabe el uso --full.

Finalmente, hay confusión terminológica: Desafortunadamente, rails plugin -hmuestra las siguientes descripciones:

[--full] # Genera un motor de rieles con la aplicación Rails incluida para realizar pruebas
[--mountable] # Genera una aplicación aislada montable

Esto da la impresión de que se utiliza --fullpara crear un "motor" y --mountablepara crear algo más llamado "aplicación montable", cuando en realidad ambos son motores: uno con espacio de nombres y el otro no. Eso seguramente generará confusión, ya que los usuarios que buscan crear un motor probablemente asumirán que --fulles la opción más relevante.

Conclusión

  • rails plugin new something --full= Motor en el espacio de nombres de su aplicación. (¿Por que lo harias?)
  • rails plugin new something --mountable= Motor con su propio espacio de nombres. (Increíble)

Referencias

Yarin
fuente
9
Hay una buena razón para usarlo --full: si tiene partes de un sitio web de rieles, desea mantenerlo integrado (no en un espacio de nombres aislado) y aún compartir entre diferentes proyectos de rieles. También puede ser más simple que eso: tal vez su gema no agregue tanto, pero desea poder engancharla correctamente.
nathanvda
2
@nathanvda - Correcto, pero creo que si está compartiendo algo en varios proyectos, realmente debería tener un espacio de nombres, porque básicamente lo está usando como un complemento
Yarin
Creo que es posible que desee usar --full si desea aislar sus archivos, el espacio de nombres de sus sitios de llamadas para cuando lo haga, Admin::AdminService.some_actionpero no tiene que cambiar sus rutas si otras aplicaciones del lado del cliente como una aplicación Ember usan las rutas relacionadas con el código que usted quiero aislar. --full parece un paso intermedio que puede ser más fácil de implementar.
Jwan622
Actualmente estoy trabajando en una aplicación internacional que necesita manejar las regulaciones específicas de cada país, pero aún expone la misma interfaz al mundo. Tengo una instancia de "Core" por país, no es necesario manejar todo a la vez. Los "motores de país" no tienen sentido por sí solos, por lo que el acoplamiento con la aplicación "central" no es un problema. Sin embargo, no quiero que estén en su propio espacio de nombres porque la aplicación principal no debe saber en qué país opera. Siento que un motor "completo" es más como organizar sus archivos y clases de una manera modular, pero manteniendo su "monolito" en su lugar.
Mankalas
17

Me preguntaba lo mismo y, por lo tanto, terminé aquí. Me parece que las respuestas anteriores básicamente cubren la pregunta, pero pensé que lo siguiente también podría ayudar:

# 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 interés (para mí) es el hecho de que no hay diferencia entre

rails plugin new test-plugin -T --mountable

y

rails plugin new test-plugin -T --full --mountable
Corey Innis
fuente
¿Quizás eso es porque --fulltiene precedencia sobre --mountable?
Mankalas
8

Mi comprensión de la diferencia es que los motores son como complementos y agregan funcionalidad a las aplicaciones existentes. Mientras que las aplicaciones montables son esencialmente una aplicación y pueden ser independientes.

Entonces, si desea poder ejecutarlo solo o dentro de otra aplicación, debería crear una aplicación montable. Si tiene la intención de que sea una adición a las aplicaciones existentes, pero no se ejecute solo, lo convertiría en un motor.

JDutil
fuente
2

La diferencia, creo, es que las aplicaciones montables están aisladas de la aplicación host, por lo que no pueden compartir clases: modelos, ayudantes, etc. Esto se debe a que una aplicación montable es un punto final de Rack (es decir, una aplicación de Rack por derecho propio ).

Descargo de responsabilidad: como la mayoría, recién comencé a jugar con Rails 3.1.

Kris
fuente
Convenido. Sin embargo, una cosa que parece extraña es que, de forma predeterminada, un motor le proporciona una carpeta de "modelos", pero una aplicación montable no. Me pregunto si la "mejor práctica" sería tener generadores que creen modelos para la aplicación incluida, ya que parece que no querría tener ninguna migración en el motor / moutable
Jeremy Raines