Rubyのalias
文化
言語によって同じ機能があってもこのように書くほうがよりその言語として適切とされるなど、特有の「文化」ができてきますが、Rubyでは「同じ役割のメソッドが別の名前で存在する」ことを肯定的に捉えるような文化があります。標準ライブラリでも、Enumerable#map
と#collect
、Array#length
と#size
のような「名前しか違わない」メソッドが多数あります。
そして、自分でそのようなメソッドを実装することも簡単にできるように、alias
構文やModule#alias_method
のような、別名を作る仕組みが存在しています。
Railsのモデルに仕掛けたら…失敗
そして、Railsのモデルについても、。「似たようなモデルで列名を調整して、ダックタイピングでまとめて扱いたい」というような場合に、カラム名メソッドのalias
をかけたくなります。ただ、素直にやってもうまく行きません。
class Person < ActiveRecord::Base
alias foo_name name
# alias_methodで書いても結果は同じ
end
こう書いてしまうと、モデルクラスのロード時にNoMethodError
となってしまいます。
何が起きた?
ActiveRecordのカラム名メソッドはテーブル定義から自動定義されますが、逆を返せば「メソッド定義のためにテーブルアクセスが必要となる」ということになります。そして、「起動時に一気にテーブル定義を取得するために詰まってしまう」という事態を避けるためもあってか、クラスロード時には即座に定義されず、メソッドの定義は必要となるまで遅延するようになっています。
ところが、alias
はクラスロード時に処理されるので、その時点でメソッドがまだ存在しないため、エラーとなってしまいます。
フルコースのalias_attribute
さすがはRails、こんな状況にも使えそうなalias_attribute
というのを用意しています。
ただ、これでalias_attribute :foo_name, :name
のようにエイリアスを行うと、foo_name
だけでなく、foo_name?
やfoo_name=
など、他のカラム名メソッドまですべてできあがってしまいます。「別名での参照だけしたい」というときには、少し大げさかもしれません(これが必要になる場面が少ないからか、情報も少ないです)。
原始的なところに落ち着く
最終的には、
def foo_name
name
end
と、単なるメソッドを立てる形で落ち着きました。alias
と違って、name
は呼んだ時点で動けば(method_missing
の動作でも)いいので、メソッド定義そのものをコピーするalias
とは質的に異なります。