LoginSignup
34
26

More than 5 years have passed since last update.

Railsのカラムにaliasをかける

Posted at

Rubyのalias文化

言語によって同じ機能があってもこのように書くほうがよりその言語として適切とされるなど、特有の「文化」ができてきますが、Rubyでは「同じ役割のメソッドが別の名前で存在する」ことを肯定的に捉えるような文化があります。標準ライブラリでも、Enumerable#map#collectArray#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とは質的に異なります。

34
26
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
34
26