Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
141
Help us understand the problem. What is going on with this article?
@kidach1

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

141
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
kidach1
Qiitaの運営方針に疑問があるため、基本的に今後の投稿は考えていません。 主に https://twitter.com/kidach1 で活動報告しています。
aktsk
株式会社アカツキは、スマートフォンゲームの企画開発を中心に事業を展開しております。創業以来全てのゲームを内製しているため、高い技術ノウハウが蓄積されています。今後は、新規事業の立ち上げも行ってまいります。

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
141
Help us understand the problem. What is going on with this article?