Edited at

Gem、Railtieプラグイン、Engine(full/mountable)の違いとそれぞれの基礎情報

More than 5 years have passed since last update.

特にRailtie、Engine(full/mountable)あたりの区分けについて、日本語の情報があまり見当たらなかったためメモします。


TL;DR


  • 汎用的なRubyスクリプトをGem化したい時はbundle gem <gem_name>

  • Railsのレールに乗ってプラグインを作りたい時はEngine(こちらもGemとして配布可能)。

  • Railtieの仕組み自体はRails全体に通ずるため理解しておきたい。

  • Full EngineとMountable Engineの違いはホストアプリケーションとの結合度。


Gem

RubyGems経由で公開されているRuby製のライブラリ全般。

よってRailtieプラグインやEngineもGemの中に含まれる。

最もシンプルに(Railsの文脈に囚われずに)作っていきたい場合は以下コマンドで作成。


生成コマンド

bundle gem <gem_name> -t

-tでspecファイルを一緒に生成してくれます。


もう少し詳しく

はじめてのgem作成

http://shiro-16.hatenablog.com/entry/2014/03/12/001402

君がOpsでもRubyで書いたライブラリはGemで配ろう

http://qiita.com/sawanoboly/items/ede7715c605e5822ad22

bundlerを使ってRSpecを書きつつGemを開発する

http://qiita.com/kakkunpakkun/items/4271973425e151afbd1a


Railtieプラグイン


そもそもRailtieとは

Rails公式のプラグイン機構で、RailsのあらゆるコンポーネントはRailtieの機能を保有している。

Railtieに基づいたプラグインを部品として組み合わせていくことで、Railsの初期化処理(イニシャライザ)やジェネレータ(rails generate ~)、Rakeタスク、設定項目(config)等々コアな部分を手軽に拡張していくことが出来る。

その本体は

module MyPlugin

class Railtie < Rails::Railtie
# config.my_plugin = ...
# initializer "my_lugin.set_configs" ...
end
end

であり、コメントのようにconfigやinitiaizerを追加の上でRailsアプリケーションから読み込むことで、Railsの一部となり拡張が実現される。

ちなみに、Action Mailer, Action Controller, Action View, Active RecordなどももちろんRailtieの機構を用いているが、それはあらゆるRailsアプリケーションのconfig/application.rbを見れば明らかになる。


config/application.rb

# Pick the frameworks you want:

require "active_model/railtie"
require "active_record/railtie"
require "action_controller/railtie"
require "action_mailer/railtie"
require "action_view/railtie"
require "sprockets/railtie"



RailtieこそがRailsの世界を司る

パーフェクトRuby on Rails引用の、Railtie/Engine/Applicationの関係を示した疑似コード。

module Rails

class Railtie
end

class Engine < Railtie
end

class Application < Engine
end

end

Railtieが全ての基本となり、さらにEngineがあり、その上にApplication(日常的な文脈における所謂「Rails」)がある。


Railtieプラグイン

Railtieの機能を保持したプラグインを生成するには、以下コマンドを利用すると手軽。


生成コマンド

rails plugin new <plugin_name>


もう少し詳しく

Rails::Railtie

http://api.rubyonrails.org/classes/Rails/Railtie.html

Railtie を使った Rails3の拡張 (翻訳版)

http://www.engineyard.co.jp/blog/2013/extending-rails-3-with-railties/

※ Railtieプラグインの事例は少ない様子。

ちょっと気の利いたものを作る時は、Engineの方がより親切にRailを敷いてくれているからかもしれません。

しかし上述のように結局はEngineもRailtieの仕組みを継承しているだけなので、Railtieのことはよく理解しておくと良いです。


Engine(Full Engine)

よりRailsアプリケーションの中身に踏み込みたい時、つまり、既存アプリのControllerやModel、Routing等を拡張したい時に利用。

Railtieと異なる点として、デフォルトでいくつかinitializerが組み込まれており、

Engineのapp,lib,configディレクトリ配下のファイルをホストアプリケーション(Engineを使う側)が自動で認識してくれる。

DeviseDoorKeeper等が該当。


生成コマンド

rails plugin new <engine_name> --full


もう少し詳しく

Rails::Engine

http://api.rubyonrails.org/classes/Rails/Engine.html


Mountable Engine(Isolated Engine)

より独立性の高いEngine。

ホストアプリケーションから完全に独立している、つまり単体で小さなRailsアプリケーションとして動作可能。

隔絶された独自のRoutingやNamespaceを持つ。

ActiveAdmin等が該当。


生成コマンド

rails plugin new <engine_name> --mountable


もう少し詳しく

使いやすくなった Rails 3.1 の Engine

http://d.hatena.ne.jp/passingloop/20110801/p1

(文中の「それ、プラグインでできるよ」は「Railtieプラグイン」のことだと思われます)

rails pluginコマンドで簡単に出来るgemの作成方法。

http://qiita.com/camelmasa/items/44ceb6ea1a3c727bc567

(「Mountable Engine」という言葉は出てこないが、それの話)


Full Engine と Mountable Engine


ざっくりユースケースの違い


Full Engine


  • ホストアプリケーションの延長として使えるので「ちょっと拡張したい」という場合は便利。

  • RoutingやNamespaceがコンフリクトする可能性がある。


Mountable Engine


  • ホストアプリケーションとコンフリクトする心配無し。

  • Engine自体が複雑な場合はMountableで完全に分離するのが吉か。


Routingの拡張を例に思想の違いを見る


Full Engine

ホストアプリケーション側のroutes.rbに特に何も書かずとも、Engineのroutes.rbの中身を勝手に継承してくれる。


hostapp/config/routes.rb

Rails.application.routes.draw do

end


my_engine/config/routes.rb

Rails.application.routes.draw do

get 'foo' => 'bar'
end

この状態でhostapp側でルーティング確認すると

 $ rake routes

Prefix Verb URI Pattern Controller#Action
foo GET /foo(.:format) bar#foo

Engineのroutesが継承されている。

手軽だけどぶつかるリスクもありますね。


Mountable Engine


hostapp/config/routes.rb

Rails.application.routes.draw do

mount MyEngine::Engine => "/my_engine" # /my_engine以下にMyEngineのルーティングをmount
end


my_engine/config/routes.rb

MyEngine::Engine.routes.draw do

get 'foo' => 'bar'
end

ルーティングを確認

 $ rake routes

Prefix Verb URI Pattern Controller#Action
my_engine /my_engine MyEngine::Engine

Routes for MyEngine::Engine:
foo GET /foo(.:format) my_engine/bar#foo

実際のアクセスURLとしては、/my_engine/foo

EngineはEngine、ときちっと分離している。


もう少し詳しく

Getting Started with Engines

http://guides.rubyonrails.org/engines.html

Engines – Mountable or Full?

http://www.astjohn.ca/2011/08/06/rails-31-engines-mountable-or-full-part-1

Engine vs. Mountable App

http://stackoverflow.com/questions/6118905/rails-3-1-engine-vs-mountable-app


その他参考

パーフェクトRuby on Rails

Defining Gems, Plugins, Railties, and Engines

http://hawkins.io/2012/03/defining_plugins_gems_railties_and_engines/

rails/rails engine.rb

https://github.com/rails/rails/blob/master/railties/lib/rails/engine.rb


最後に

今のところ公式APIドキュメント(原文)をあたるのが一番早くて正確そうです。

とはいえ日本語でも正確な情報が増えると良いですね!