Railsのプラグインを作る基礎テク
developmentモードとproductionモード
今日チームのメンバーに聞かれて気付いたことですが、developmentモードが便利過ぎるからか、リクエストが来るたびにコントローラのクラスがロードされるように勘違いする人もいるみたいです。
プラグインを作るときにはproductionモードとdevelopmentモードの違いを把握しておかないと、プラグインを作るのに困るので、念のため書いておきます。
考え方としては、基本はproductionモードです。productionモードで各ファイルは基本的に一度しかロードされません。それだとコードを変更するたびに反映させるためにはにいちいちサーバーを再起動させなければならないので、開発時はあまりにも大変なので、Railsのdeveloppmentモードでは特殊な仕組みで、リクエストが来るたびに必要なファイルをロードします。
const_missingと命名規則
Rubyではファイルをロードするためには、通常requireあるいはloadメソッドを使いますが、通常Railsアプリではモデルやコントローラの定義してあるファイルをrequireする必要はありません。
これは、どうなっているかというとRubyにはModule#const_missing( http://www.ruby-lang.org/ja/man/html/Module.html#const_missing )というメソッドありまして、参照しようとした定数が存在しないときに呼び出されるようになっています。
Railsではこのconst_missingメソッドを拡張して、参照しようとした定数がないと、命名規則からそれが定義されているはずのファイル名を求めそれをロード(developmentモードではload、productionモードではrequire)します。
この辺の実装は、activesupportのlib/active_support/dependencies.rbにあります。
alias_method_chain
通常のプラグインでは、モジュール(クラスを含む)で宣言されているメソッドの振る舞いを変更する場合、alias_method_chainを使います。これはactivesupportのlib/active_support/core_ext/module/aliasing.rbに定義されているメソッドで、以下のようなことができます。
require 'rubygems' require 'active_support' class A def foo "foo" end def foo_with_hoge foo_without_hoge + " with HOGE" end alias_method_chain :foo, :hoge end a = A.new a.foo # => "foo with HOGE" a.foo_with_hoge # => "foo with HOGE" a.foo_without_hoge # => "foo"
実はalias_method_chainを使わなくてもこんな書き方でも同じようなことができます。
# alias_method_chain :foo, :hoge alias_method :foo_without_hoge, :foo alias_method :foo, :foo_with_hoge
alias_methodは元々Rubyにあるメソッドです。http://www.ruby-lang.org/ja/man/html/Module.html#alias_method
要は元々あるメソッドに_without_hogeを後ろにくっつけた名前で別名を付けて、拡張するメソッドを元々のメソッドの名前の別名を付けて上書きしちゃいます。