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

  • 100
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

特に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ドキュメント(原文)をあたるのが一番早くて正確そうです。
とはいえ日本語でも正確な情報が増えると良いですね!