Rails 3.1: motore e app montabile


120

Qualcuno può aiutarmi a capire le differenze tra un Rails Engine e un'app Mountable? In Rails 3.1, puoi crearne uno con il comando "rails new plugin _ __ ".

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

Quando vorresti usarne uno rispetto all'altro? So che puoi impacchettare un motore come una gemma, per esempio. Non è così per le app montabili? Quali altre differenze ci sono?

Risposte:


143

Ho notato quanto segue:

Motore completo

Con un motore completo, l'applicazione padre eredita i percorsi dal motore. Non è necessario specificare nulla in parent_app/config/routes.rb. Specificare la gemma in Gemfile è sufficiente affinché l'app genitore erediti i modelli, i percorsi, ecc. I percorsi del motore sono specificati come:

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

Nessuno spazio dei nomi di modelli, controller, ecc. Questi sono immediatamente accessibili all'applicazione principale.

Motore montabile

Lo spazio dei nomi del motore è isolato per impostazione predefinita:

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

Con un motore montabile, le rotte sono con spazio dei nomi e l'app genitore può raggruppare questa funzionalità in una singola rotta:

# 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 

I modelli, i controller, ecc. Sono isolati dall'applicazione principale, sebbene gli helper possano essere condivisi facilmente.

Queste sono le principali differenze che ho notato. Forse ce ne sono altri? Ho chiesto qui , ma devo ancora ricevere una risposta.

La mia impressione è che, poiché un motore completo non si isola dall'applicazione principale, è meglio utilizzarlo come applicazione autonoma adiacente all'app principale. Credo che potrebbero verificarsi conflitti di nome.

Un motore montabile può essere utilizzato in situazioni in cui si desidera evitare conflitti di nome e raggruppare il motore in un percorso specifico nell'applicazione padre. Ad esempio, sto lavorando alla costruzione del mio primo motore progettato per il servizio clienti. L'applicazione genitore potrebbe raggruppare le sue funzionalità in un unico percorso come:

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

Se le mie ipotesi sono troppo lontane, qualcuno me lo faccia sapere e correggerò questa risposta. Ho fatto un piccolo articolo sull'argomento qui Saluti!


1
Un motore montabile può mai essere instradato / montato nella radice dell'app principale?
Slick23

3
@JustinM potresti provare mount MyEngine::Engine => "/". Funziona per le risorse, forse è anche il caso dei motori.
Benoit Garret

2
@astjohn Ottimo riassunto dei tuoi blog. Ma non sarebbe il contrario? Un Full Engine sarebbe "incompleto" e necessita dell'app genitore per funzionare, mentre Mountable Engine può funzionare da solo, poiché è "isolato" dall'app genitore?
Theo Scholiadis

39

Entrambe le opzioni genereranno un motore . La differenza è che --mountablecreerà il motore in uno spazio dei nomi isolato, mentre --fullcreerà un motore che condivide lo spazio dei nomi dell'app principale.

Le differenze si manifesteranno in 3 modi:

1) Il file della classe motore chiamerà 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) Il config/routes.rbfile del motore avrà uno spazio dei nomi:

Motore completo:

Rails.application.routes.draw do
end

Motore montato:

MyMountableEngine::Engine.routes.draw do
end

3) La struttura dei file per i controller, gli helper, le viste e le risorse sarà a spaziatura dei nomi:

crea app / controllers / my_mountable_engine /application_controller.rb
crea app / helpers / my_mountable_engine /application_helper.rb
crea app / mailers crea app / modelli
crea app / views / layouts / my_mountable_engine /application.html.erb
crea app / assets / images / my_mountable_
create app / assets / stylesheets / my_mountable_engine /application.css
create app / assets / javascripts / my_mountable_engine /application.js
create config / routes.rb create lib / my_mountable_engine.rb
create lib / tasks / my_mountable_engine.rake
create lib / my_mountable_engine / version .RB
creare lib / my_mountable_engine / engine.rb


Spiegazione

Il caso d'uso --fulldell'opzione sembra essere molto limitato. Personalmente non riesco a pensare a nessuna buona ragione per cui vorresti separare il tuo codice in un motore senza isolare anche lo spazio dei nomi: essenzialmente ti darebbe solo due applicazioni strettamente accoppiate che condividono strutture di file identiche e tutti i conflitti e la perdita di codice ciò comporta.

Ogni parte della documentazione che ho visto dimostra l' --mountableopzione, e in effetti l'attuale guida ai margini ti incoraggia fortemente a includere isolate namespace- che è lo stesso che dire use --mountableover --full.

Infine c'è confusione terminologica: sfortunatamente rails plugin -hmostra le seguenti descrizioni:

[--full] # Genera un motore rails con l'applicazione Rails in bundle per i test
[--mountable] # Genera un'applicazione isolata montabile

Questo dà l'impressione che tu usi --fullper creare un "motore" e --mountableper creare qualcos'altro chiamato "applicazione montabile", quando in realtà sono entrambi motori - uno con spazio dei nomi e uno no. Ciò è destinato a creare confusione poiché gli utenti che cercano di creare un motore probabilmente presumeranno che --fullsia l'opzione più pertinente.

Conclusione

  • rails plugin new something --full= Engine nello spazio dei nomi della tua app. (Perchè vorresti?)
  • rails plugin new something --mountable= Motore con il proprio spazio dei nomi. (Eccezionale)

Riferimenti


9
C'è una buona ragione per usarlo --full: se hai parti di un sito web rails che vuoi mantenere integrate (non in uno spazio dei nomi isolato) e condividerle comunque tra diversi progetti rails. Inoltre può essere più semplice di così: forse la tua gemma non aggiunge molto, ma vuoi essere in grado di agganciarla correttamente.
nathanvda

2
@nathanvda - Giusto, ma penso che se condividi qualcosa su più progetti dovrebbe davvero avere uno spazio dei nomi, perché fondamentalmente lo stai usando come plug-in
Yarin

Penso che potresti voler usare --full se vuoi isolare i tuoi file, lo spazio dei nomi dei tuoi siti di chiamata per quando lo fai, Admin::AdminService.some_actionma non devi cambiare i tuoi percorsi se altre applicazioni lato client come un'app Ember usano i percorsi relativi al codice che tu voglio isolare. --full sembra un passaggio intermedio che potrebbe essere più facile da implementare.
Jwan622

Attualmente sto lavorando a un'applicazione internazionale che deve gestire le normative specifiche del paese, ma espone la stessa interfaccia al mondo. Ho un'istanza di "Core" per paese, non è necessario gestirle tutte in una volta. I "motori country" non hanno senso da soli, quindi l'accoppiamento con l'app "core" non è un problema. Tuttavia, non voglio che siano nel proprio spazio dei nomi perché l'app principale non deve sapere in quale paese opera. Penso che un motore "completo" sia più come organizzare i tuoi file e le tue classi in modo modulare, mantenendo comunque il tuo "monolite" al suo posto.
Mankalas

17

mi chiedevo la stessa cosa e, quindi, sono finito qui. mi sembra che le risposte precedenti coprano sostanzialmente la domanda, ma ho pensato che anche quanto segue potrebbe aiutare:

# 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

di particolare interesse (per me) è il fatto che non c'è differenza tra

rails plugin new test-plugin -T --mountable

e

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

Forse perché --fullha la precedenza su --mountable?
Mankalas,

8

La mia comprensione della differenza è che i motori sono come plugin e aggiungono funzionalità alle applicazioni esistenti. Sebbene le app montabili siano essenzialmente un'applicazione e possono essere autonome.

Quindi, se vuoi essere in grado di eseguirlo da solo o all'interno di un'altra applicazione, dovresti creare un'app montabile. Se intendi che sia un'aggiunta alle applicazioni esistenti, ma non eseguito da solo, ne faresti un motore.


2

La differenza, credo, è che le app montabili sono isolate dall'app host, quindi non possono condividere classi - modelli, helper ecc. Questo perché un'app montabile è un endpoint Rack (cioè un'app Rack a sé stante ).

Dichiarazione di non responsabilità: come la maggior parte, ho appena iniziato a giocare con Rails 3.1.


Concordato. Una cosa che sembra strana però è che, per impostazione predefinita, un motore ti dà una cartella "modelli", ma un'app montabile no. Mi chiedo se la "migliore pratica" sarebbe quella di avere generatori che creano modelli per l'app inclusa, dal momento che sembra che non vorresti avere alcuna migrazione nel motore / moutable
Jeremy Raines
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.