Rails 2.3のengine機能を調べてみた

どんなものかしら、と思って調べてみました。実はenginesとか(Merbのsliceとか)懐疑派だったんですが、最近になっていくつか良さそうなユースケースが思いついたんで、うまくやれないかな、と。
これまで懐疑派だった償い?として、rails-enginesチームの公式ブログの記事を意訳してみました。

http://rails-engines.org/news/2009/02/02/engines-in-rails-2-3/

後半は疲れてきたので、特に訳が粗くなっていますが、何かあればコメントやIRCなどでツッコミください。

Engines in Rails 2.3

Some support for ‘engine’ plugins has been merged into the Rails core codebase in Rails 2.3. In this guide, I’ll try to explain what works, what has changed, and what is currently missing compared to the original engines plugin.

engines pluginのいくつかの機能がRails2.3本体のコードベースにマージされました。ここでは、何が取り込まれたか、どのような変更があったか、そして今のところ取り込まれていない元のプラグインの機能はどんなものがあるのか、説明しますね。

What works (そのまま動くこと)

The core of the engines plugin has always been sharing controllers, models and views seamlessly from within a plugin. I’m glad to say that this is now fully supported by Rails itself. The same app/controllers and app/models folders will be added to the $LOAD_PATH in the appropriate order.

engines pluginのコアとなる機能は、プラグイン内のコントローラ、モデル、ビューをシームレスに使えるようにすることです。いまや、それがRails本体でサポートされるようになったというのはとっても素敵ですよね。(訳注: これまでのengines pluginとおなじ / "The same")app/controllersとapp/modelsディレクトリがアプリケーションの$LOAD_PATHに追加されます。

Secondly, loading views also works in the same way you’d expect. This means that you can override views and partials in your application, just like with the original engines plugin.

さらに、ビューテンプレートのロードも期待通り動きます。つまり、アプリケーション独自のビューを置けば、それで上書きされて動くわけです。コレは、従来のengines pluginと同じですね。

What has changed (変わったこと)

Rails 2.3 also brings support for loading routes from plugins, but the technique has slightly changed. With Rails 2.3, create your routing file in your plugin as config/routes.rb (the engines plugin did not require the config directory).

Rails 2.3 ではプラグインで定義したルーティングのロードもサポートしていますが、ちょっと変更があります。Rails 2.3ではルーティングをプラグインのconfig/routes.rbにて定義します(元のenginesではconfigディレクトリの外に置いていました)。

The other change is that they should be formatted as a normal routing file. For example, with the file app/controllers/awesome_controller.rb in your plugin, the config/routes.rb could be

(ルーティング周りでの)もう一つの変更点は、このルーティングのフォーマットが、ふつうの(Rails本体の)ルーティングと同じフォーマットになっていることです。たとえば、app/controller/awesome_controller.rbがプラグインにあったとすると、ルーティングはこうなるでしょう。

ActionController::Routing::Routes.draw do |map|
  map.blah '/awesome', :controller => 'awesome'
end

The main difference here is that you need to include the ActionController::Routing::Routes.draw line.

一番の違いは、ActionController:Routing::Routes.drawの行を入れるようになったことです。

What is missing (まだないもの)

Sadly, there are a few features of the engines plugin that have not been ported to Rails 2.3 yet. Those are:

残念ながら、現時点ではRails 2.3に取り込まれていない機能もあります。

Migrations from plugins (プラグインからのマイグレーション)

It’s not possibly to run migrations from plugins with Rails 2.3. There are a number of reasons for this, but principally the problem comes from needing to be able to determine which migrations from which plugins have already run.

Rails 2.3ではプラグインからマイグレーションを実行できません。コレはいくつか理由がありますが、一番の理由はどのプラグインマイグレーションが実行されていて、どれがまだなのかを判別しなきゃいけないからです。

If you’re using timestamped migrations there is no problem, since the likelihood of a timestamp collision is quite low. In this case, I would recommend writing a simple task or script to copy migrations from your plugin into the main db/migrate directory. It’s important that the migrations are anchored in some way to the main migration directory, since some folks use migrations to recreate their database rather than schema.rb, and so the set of migrations should accurately reflect the actual state of the application at any point in time.

もしもタイムスタンプのついたマイグレーションであれば、タイムスタンプが衝突することはほとんどないでしょうから、問題ないはずです。この場合はちょっとしたマイグレーションタスクを作るか、プラグインのdb/migrateディレクトリからコピってくればいいでしょう。

If you are not using timestamped migrations, this is a bigger problem. Imagine you are developing your application, and have several migrations:

タイムスタンプ付きのマイグレーションを使っていない場合、だいぶ難しいです。例えばこんなマイグレーションがあるとします

/my_app/db/migrate/001_create_users.rb
/my_app/db/migrate/002_add_widgets.rb
/my_app/db/migrate/003_reticulate_splines.rb

You then install a plugin with some migrations:

で、プラグインからこんなマイグレーションを入れると

/my_app/vendor/plugins/my_plugin/db/migrate/001_install_the_awesome.rb

We now have two migrations with the version ‘1’ - one from the app (which has probably already run), and one pending from the plugin. There’s no way to tell, at the moment, that the plugin migration needs to be run.

バージョンが1なマイグレーションが二つ、つまりひとつはアプリケーショのヤツで実行済みのもの、もう一つはプラグインので未実行のものができます。ここから、プラグインのものが未実行であると言うのを簡単に判別する手段がないのです。

I have some ideas for how to fix this, and so hopefully we’ll see some progress soon.

これを直すアイディアはいくつかあるので、何かしら案を出すつもりです。

Public Assets in plugins (publicやassetsのファイル)

The engines plugin will mirror files from public or assets directories into the main application public directory, so that those files can be served directly to browsers. The plugin also augmented some of the view helpers so they could reference these files.

engines pluginではpublicとassetsディレクトリ内のファイルをアプリ側のpublicディレクトリにミラーするため、これらのファイルは(訳注:Webサーバがさばくので)そのままブラウザに送信されます。また、ビューのヘルパーも拡張しているため、これらのファイルを参照することもできました。

Rails 2.3 won’t automatically do this for you, but it shouldn’t be too arduous to write a few lines of code in init.rb to copy files into the public directory. However, without the helper additions of the engines plugin, your files won’t be automatically ‘namespaced’ according to plugin, so if two plugins try to copy a file called styles.css, one will overwrite the other. The solution? Try copying your files to a unique filename or subdirectory to avoid these clashes.

Rails 2.3はこういうことを自動的にやってくれません。ただ、init.rbにファイルをコピーするコードを足すだけなので、そんなに大変ではないでしょう。しかし。engines pluginのようなヘルパーの拡張がないため、"namespaced"な配置にはならず、複数のプラグインがstyle.cssのような同じ名前のファイルをコピーしようとすると上書きされたりとひどい目に遭います。解決策? ファイル名が一位になるとかサブディレクトリ作るとか、ガンバレ!!

Code mixing (コードのmixin)

Rails 2.3 doesn’t attempt to do any of the ‘code mixing’ that the engines plugin does. For those of you not in the know, this is the functionality that lets your application override a single method in a controller or helper, without having to copy the whole file from the plugin into your application.

Rails 2.3は、engines pluginがやっていた'code mixing'的なことはやってくれません。知らない人のために説明すると、これはアプリケーション側のコントローラやヘルパーでプラグインの昨日を上書きするための仕組みです。これがあると、プラグインの中身をアプリ側にコピーする必要がなくなります。

I cannot say for sure, but I doubt this feature will ever make it into Rails itself, and to be honest, I think that’s probably a good thing. While the code mixing mechanism is quite neat, there are other ways of overriding the implementation of methods which are more typically Rubyish, and involve less magic. I’ll try and post some examples here soon.

確かなことはいえませんけど、この機能はRailsが今後実装するかどうか疑問です。正直なところ、これはいいことじゃないかと思います。このcode mixingの仕組みはよくできてはいましたが、もっとRubyっぽく、黒魔術的じゃない方法で実装をオーバーライドする方法があるんじゃないかと思ってます。いい例ができたらあとで書く。

There you go

I hope that’s outlined the engines support in Rails 2.3 in a reasonably clear way. I hope that we’ll be able to merge some of the simpler missing features into the core (migrations and assets, notable) soon. Maybe you’re the one to write that patch? PDI :)

こんな感じで、Rails 2.3のenginesのサポートをうまく説明したつもりです。今後も、欠けている機能のうちシンプルなもの(特にmigrationとassets)をRails本体にマージしていきたいと思ってます。と言うことで皆さん、パッチをお待ちしていますよ :)