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 как драгоценный камень, например. Разве это не относится к подключаемым приложениям? Какие еще есть отличия?

Джереми Рейнс
источник

Ответы:

143

Я заметил следующее:

Полный двигатель

В случае полного движка родительское приложение наследует маршруты от движка. Не нужно ничего указывать в parent_app/config/routes.rb. Указать гем в Gemfile достаточно, чтобы родительское приложение унаследовало модели, маршруты и т. Д. Маршруты движка указываются как:

# 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" 

Если я ошибаюсь в своих предположениях, дайте мне знать, и я исправлю этот ответ. Я сделал небольшую статью на эту тему здесь Ура!

astjohn
источник
1
Может ли монтируемый движок когда-либо маршрутизироваться / монтироваться в корне родительского приложения?
Slick23,
3
@JustinM вы можете попробовать mount MyEngine::Engine => "/". Это работает для ресурсов, возможно, это также относится к двигателям.
Бенуа Гаррет
2
@astjohn Отличное подведение итогов ваших блогов. Но разве не было бы наоборот? Будет ли Full Engine «неполным» и требовать для работы родительского приложения, в то время как Mountable Engine может работать автономно, поскольку он «изолирован» от родительского приложения?
Theo Scholiadis 05
39

Оба варианта сгенерируют двигатель . Разница в том --mountable, что движок будет создан в изолированном пространстве имен, тогда как --fullбудет создан движок, который разделяет пространство имен основного приложения.

Различия проявятся 3 способами:

1) Файл класса движка будет вызывать isolate_namespace:

Библиотека / my_full_engine / engine.rb:

module MyFullEngine
  class Engine < Rails::Engine
  end
end

Библиотека / 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) Файловая структура для контроллеров, помощников, представлений и ресурсов будет иметь пространство имен:

create app / controllers / my_mountable_engine /application_controller.rb
create app / helpers / my_mountable_engine /application_helper.rb
create app / mailers create app / models
create app / views / layouts / my_mountable_engine /application.html.erb
create app / assets / images / my_mountable
создать app / assets / stylesheets / my_mountable_engine /application.css
создать приложение / 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 .rb
создать lib / my_mountable_engine / engine.rb


объяснение

Вариант использования этой --fullопции кажется очень ограниченным. Лично я не могу придумать какой-либо веской причины, по которой вы хотели бы разделить свой код в движок, не изолировав также пространство имен - по сути, это просто даст вам два тесно связанных приложения, совместно использующих идентичные файловые структуры, и все конфликты и утечку кода. что влечет за собой.

Каждая часть документации , которую я видел демонстрирует --mountableвариант, и на самом деле текущий руководство края настоятельно рекомендует вам включить isolate namespace- что то же самое , как говорят использование --mountableболее --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. Также это может быть проще: возможно, ваш драгоценный камень не так много добавляет, но вы хотите иметь возможность правильно его подключить.
nathanvda
2
@nathanvda - Верно, но я думаю, что если вы делитесь чем-то в нескольких проектах, это действительно должно быть в пространстве имен, потому что вы в основном используете это как плагин
Ярин
Я думаю, вы можете использовать --full, если хотите изолировать свои файлы, пространство имен для ваших сайтов вызовов, когда вы это делаете, Admin::AdminService.some_actionно не должны изменять свои маршруты, если другие клиентские приложения, такие как приложение Ember, используют маршруты, связанные с кодом, который вы хочу изолировать. --full кажется промежуточным шагом, который может быть проще реализовать.
Jwan622
В настоящее время я работаю над международным приложением, которое должно обрабатывать правила конкретной страны, но при этом предоставляет тот же интерфейс для всего мира. У меня есть по одному экземпляру Core на страну, не нужно обрабатывать все сразу. «Двигатели страны» сами по себе не имеют смысла, поэтому связь с «основным» приложением не является проблемой. Однако я не хочу, чтобы они находились в собственном пространстве имен, потому что основное приложение не должно знать, в какой стране оно работает. Я считаю, что «полный» движок больше похож на модульную организацию файлов и классов, но при этом сохраняет «монолит» на месте.
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

Я понимаю разницу в том, что движки похожи на плагины и добавляют функциональность существующим приложениям. В то время как монтируемые приложения по сути являются приложениями и могут работать автономно.

Поэтому, если вы хотите иметь возможность запускать его отдельно или в другом приложении, вы должны создать монтируемое приложение. Если вы хотите, чтобы он был дополнением к существующим приложениям, но не запускался сам по себе, вы бы сделали его движком.

JDutil
источник
2

Я считаю, что разница в том, что монтируемые приложения изолированы от хост-приложения, поэтому они не могут совместно использовать классы - модели, помощники и т. Д. Это связано с тем, что монтируемое приложение является конечной точкой стойки (т. Е. Приложение стойки само по себе ).

Отказ от ответственности: я, как и большинство, только начал играть с Rails 3.1.

Kris
источник
Согласовано. Одна вещь, которая кажется странной, заключается в том, что по умолчанию Engine предоставляет вам папку «models», а Mountable App - нет. Интересно, будет ли «лучшей практикой» иметь генераторы, которые создают модели для включаемого приложения, поскольку кажется, что вы не захотите иметь какие-либо миграции в движке / moutable
Джереми Рейнс