2014-03-09

rubyを2.0にあげたらrailsのfixturesで読み込む値が変わってた

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク
Rails3.2とruby1.9.3で作ったもののrubyを2.0系にあげてみたところ、rake specが失敗するようになってしまいました。

失敗するのは、日時関連の処理だったので、timezone関係のものがおかしいのかなぁと思ったのですが、fixturesでテストデータを読み込んだ動作が1.9と2.0で違っていました。

具体的には、fixturesで
aaa: 2014-01-25 22:57:09
と書いていたところが、おかしかったようです。

さらに調べたらYAM.loadで読み込んだ時点で違っていました。
rails cでコンソールを立ち上げてそれぞれのバージョンで比較した結果は、以下のとおりです。

1.9.3
[1] pry(main)> a = "aaa: 2014-01-25 22:57:09"
=> "aaa: 2014-01-25 22:57:09"
[2] pry(main)> YAML.load(a)
=> {"aaa"=>"2014-01-25 22:57:09"}
[3] pry(main)> YAML.load(a)["aaa"].class
=> String

2.0.0
[1] pry(main)> a = "aaa: 2014-01-25 22:57:09"
=> "aaa: 2014-01-25 22:57:09"
[2] pry(main)> YAML.load(a)
=> {"aaa"=>2014-01-26 07:57:09 +0900}
[3] pry(main)> YAML.load(a)["aaa"].class
=> Time

YAML.loadが定義されているところを調査してみました。

1.9.3
[1] pry(main)> YAML.method(:load)
=> #<Method: Syck.load>

2.0.0
[1] pry(main)> YAML.method(:load)
=> #<Method: Psych.load>

なんかloadが定義されている場所が違いました。

調べてみると以下のようなことでした。
http://qiita.com/udzura/items/ec4c5b83db94363c9cdf
Syckは古いもののようで、2.0.0からはなくなったようです。

1.9.3でもPsychがデフォルトのようなのですが、railsがSyckがあればそちらを優先している気配です。
今回の例は、あくまでもrails cでコンソールを利用している場合で、railsを利用しないでpryで実行すると1.9.3でも2.0.0でも動きはPsychの動きをしていました。

ちなみに以下のように1.9.3でもPsychを指定すれば2.0.0と同じ動きをします。

[1] pry(main)> YAML::ENGINE.yamler = 'psych'
=> "psych"
[2] pry(main)> a = "aaa: 2014-01-25 22:57:09"
=> "aaa: 2014-01-25 22:57:09"
[3] pry(main)> YAML.load(a)
=> {"aaa"=>2014-01-26 07:57:09 +0900}
[4] pry(main)> YAML.load(a)["aaa"].class
=> Time

で、今回は、"2014-01-25 22:57:09"を日本時間のつもりで書いていたのに、違う解釈をされたのが困ったのでした。
これを解決するには、日付は以下のようにすることで1.9.3でも2.0.0でも同じ動きをするようになります。
aaa: 2014-01-25 22:57:09 +09:00

[1] pry(main)> a = "aaa: 2014-01-25 22:57:09 +09:00"
=> "aaa: 2014-01-25 22:57:09 +09:00"
[2] pry(main)> YAML.load(a)
=> {"aaa"=>2014-01-25 22:57:09 +0900}
[3] pry(main)> YAML.load(a)["aaa"].class
=> Time