RailsでtimeとdatetimeとSQLiteとMySQLではまる
移転しました →
RSSフィードを例にとって、僕がRailsを触っているときにはまったことを書いておきます。初歩かもしれんけどハマったもんは仕方ないし、Stackoverflow見てたら他にも同じような人がいるっぽかったんでちょっとまとめておきます。
前置き
RSSフィードは書く記事に更新日時が入っています。新しい順に並べるのが一般的なので更新日時のカラムで並べ替えて記事を並べてあげたいとします。
Entryモデルはこんな感じになっています。
# マイグレーション class CreateEntries < ActiveRecord::Migration def change create_table :entries do |t| t.string :title t.time :published t.timestamps end end end # モデル class Entry < ActiveRecord::Base default_scope {order('entries.published DESC')} # 新しい順に end
このブログの場合はこうなって欲しいです。
Chef Solo 再チャレンジ まとめ | 2013-04-16 02:15:19 UTC |
Chefでnginxを導入してみる | 2013-04-16 02:10:39 UTC |
Chefを使ってiptablesの設定を変える | 2013-04-16 01:19:33 UTC |
knifeでOPSCODEのCookbookを使う | 2013-04-16 01:01:07 UTC |
vagrantとchef-soloを体験してみる | 2013-04-15 07:52:24 UTC |
正規表現でテキストの置換ができるwebアプリ | 2013-04-07 01:18:51 UTC |
NewRelicでherokuのRailsアプリケーションのパフォーマンスを測定する | 2013-04-04 06:26:10 UTC |
WordPressでMarkdown記法を使う | 2013-04-03 05:10:09 UTC |
RSpec+Spork+Guardの環境で :js => trueのテストを無視する | 2013-03-28 13:23:04 UTC |
カラースキームからTwitter Bootstrapのテーマを作成する | 2013-03-19 04:46:33 UTC |
ところが、MySQLを使うproduction環境では次のようになってしまいました。
RSpec+Spork+Guardの環境で :js => trueのテストを無視する | 2000-01-01 13:23:04 UTC |
vagrantとchef-soloを体験してみる | 2000-01-01 07:52:24 UTC |
NewRelicでherokuのRailsアプリケーションのパフォーマンスを測定する | 2000-01-01 06:26:10 UTC |
WordPressでMarkdown記法を使う | 2000-01-01 05:10:09 UTC |
カラースキームからTwitter Bootstrapのテーマを作成する | 2000-01-01 04:46:33 UTC |
Chef Solo 再チャレンジ まとめ | 2000-01-01 02:15:19 UTC |
Chefでnginxを導入してみる | 2000-01-01 02:10:39 UTC |
Chefを使ってiptablesの設定を変える | 2000-01-01 01:19:33 UTC |
正規表現でテキストの置換ができるwebアプリ | 2000-01-01 01:18:51 UTC |
knifeでOPSCODEのCookbookを使う | 2000-01-01 01:01:07 UTC |
更新日時がめちゃくちゃになっているのがわかります。そのせいか並び順もおかしくなっています。
確認その1 更新日時がおかしい
フィードを解析して得られる日時は正しい日付が入っていることはデバッグして確認できています。データベースに入れるときにおかしくなっているのだと考えました。
Rails consoleを使って次のように試してみると、、、
entry_data = feeddata.entries.first e = Entry.new(title:entry_data.title, published:entry_data.published) p e.published # => 2013-05-10 23:35:07 +0900 e.save p e.reload.published # => 2000-01-01 14:35:07 UTC !!!
こんな風になってしまうのでした。 ここではそもそもtimeを使おうとしていたのが間違いでした。timeでは日付部分は保存されないのでdatetimeを使わないといけません。
class CreateEntries < ActiveRecord::Migration def change create_table :entries do |t| t.string :title t.datetime :published # <= ここを直す t.timestamps end end end
これで日付は直ります。
確認その2 並び順がおかしい
前述のtimeを使用すると日付がおかしくなる(丸められると言ってもいいでしょう)ことは実はSQLite、MySQLともに起こります。問題というか、仕様ですかね。
ところが、sqliteを使っているdevelopment環境では順番がおかしくならなかったため気がつくのが遅れました。日付がおかしくてもたまたまうまいこと欲しい順番で結果が返ってきていたというわけです。
Chef Solo 再チャレンジ まとめ | 2000-01-01 02:15:19 UTC |
Chefでnginxを導入してみる | 2000-01-01 02:10:39 UTC |
Chefを使ってiptablesの設定を変える | 2000-01-01 01:19:33 UTC |
knifeでOPSCODEのCookbookを使う | 2000-01-01 01:01:07 UTC |
vagrantとchef-soloを体験してみる | 2000-01-01 07:52:24 UTC |
正規表現でテキストの置換ができるwebアプリ | 2000-01-01 01:18:51 UTC |
NewRelicでherokuのRailsアプリケーションのパフォーマンスを測定する | 2000-01-01 06:26:10 UTC |
WordPressでMarkdown記法を使う | 2000-01-01 05:10:09 UTC |
RSpec+Spork+Guardの環境で :js => trueのテストを無視する | 2000-01-01 13:23:04 UTC |
カラースキームからTwitter Bootstrapのテーマを作成する | 2000-01-01 04:46:33 UTC |
こんなふうに、日付はおかしいんだけど新しい順にならんでいるという。
これはおそらくSQLiteの際にorderが効いていないのだと考えられます。 MySQLになったときに初めてorderが有効になった、けれどそのときに使っていたカラムの値がおかしかったので順番がめちゃくちゃに見えてしまった、というのが今回ハマったところでした。
developmentとproductionのDBを揃えば住むことなので、初めからそうしたほうがいいです。身を持って経験。