ActiveRecordの予約語とテーブルのカラム名

RubyのActiveRecordActiveRecordってデザインパターン名だったんだね。知らなかった・・・。http://ja.wikipedia.org/wiki/Active_Recordライブラリを使ってDB操作をした際、ハマッたのでメモ。

ActiveRecordを使うと、DBテーブルのレコードをオブジェクトとして取り出せます。
カラムのデータを取得する際は、カラム名をメソッド名としてオブジェクトを操作すれば良いのですが、
ActiveRecordの予約語と同じカラム名が存在すると正しく動作しません。

例えば、type, displayなどが予約語です。

ためしに、下記のようにテーブルとレコードをつくり、

$ mysql -u root test

CREATE TABLE apples
(
    id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY,
    type VARCHAR(20) NOT NULL
);
INSERT INTO apples (type) VALUES ('fuji');

以下のRubyコードを書いたとします。
[Ruby]
require ‘rubygems’
require ‘activerecord’

ActiveRecord::Base.establish_connection(
:adapter => ‘mysql’,
:host => ‘127.0.0.1’,
:username => ‘root’,
:password => ”,
:database => ‘test’
)

class Apple < ActiveRecord::Base end a = Apple.find(1) p a.type [/Ruby] 上記コードを実行すると下記のような例外がでます。

/usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1434
:in `instantiate’: The single-table inheritance mechanism failed to locate 
the subclass: ‘fuji’. This error is raised because the column ‘type’ is reserved
for storing the class in case of inheritance. Please rename this column if you didn’t
intend it to be used for storing the inheritance class or overwrite 
Apple.inheritance_column to use another column for that information. 
(ActiveRecord::SubclassNotFound)

typeの場合は、上記のようにわかりやすい例外がでます。displayという名前のカラムが
ある場合は特に例外が発生しません。でも、a.displayと実行してもカラムのデータとは異なる値が
返ってくるので厄介です。

対処法としてはカラム名を変更(type -> etypeとか)するのが普通です。

カラム名を変更したくない場合はselectで別名を指定すれば、問題を回避できます。
[Ruby]
a = Apple.find(1, :select => ‘type as etype’)
p a.etype # “fuji”
[/Ruby]

ActiveRecordの予約語として何があるかは、下記リンクを見てください

その他参考文献

http://uruseiyatsura.way-nifty.com/blog/2007/08/ruby_on_rails.html