ActiveRecordの内部実装を垣間見る その1
ARの実装とRuby処理系のTimeに関する実装でハマる - Lazy Technology
にも書いたけど、ARはDBMSのカラム情報に基づいて、格納された値を自動的にキャスト(変換)する。
ar = AR.new ar.id = "hoge" => "hoge" ar.id => 0
キャストするのは格納時ではなく出力時。
オリジナルの値が欲しい場合はカラム名_before_type_castメソッドを呼ぶ。
a.id_before_type_cast => "hoge"
キャストのロジックを実装しているのはColumn#type_castメソッド。以下に定義されている。
activerecord\lib\active_record\connection_adapters\abstract\schema_definitions.rb
# Casts value (which is a String) to an appropriate instance. def type_cast(value) return nil if value.nil? case type when :string then value when :text then value when :integer then value.to_i rescue value ? 1 : 0 when :float then value.to_f when :decimal then self.class.value_to_decimal(value) when :datetime then self.class.string_to_time(value) when :timestamp then self.class.string_to_time(value) when :time then self.class.string_to_dummy_time(value) when :date then self.class.string_to_date(value) when :binary then self.class.binary_to_string(value) when :boolean then self.class.value_to_boolean(value) else value end end
ARがよく分からないバギーな動作をした時にこの辺を知っていると役立つ…のかな。
2007/5/21 追記
activerecord\lib\active_record\connection_adapters\abstract\schema_definitions.rb
に定義されているのはデフォルトのキャストロジックで、DBMSによっては個別のアダプタクラスでオーバーライドしている事もある。
activerecord\lib\active_record\connection_adapters\mysql_adapter.rb
を見る限り、MySQLでは特にオーバーライドしていない。