「Rails3でO/RマッパをDataMapperにしてsqliteを選択したときにdbファイルが作られない。」という舌をかみそうな現象に遭遇したのでご紹介。
結論から言うと、こちらのようにdatabaseではなくpathで書いてあげれば解決します。
Rails 3 DataMapper dm-rails sqlite3 issue – Ruby Forum
change "database" to "path" database: testing_dm3_development.db to path: ./db/testing_dm3_development.db
databaseのままだとファイルではなくメモリにデータが作られてしまうために、セッションが切れると飛んでしまうのが原因のようです。
・・・で、このままでは気持ち悪いのでどうしてこうなるかを追ってみました。
まず、現象はこんな感じ。(論点ではない出力は省略)
% ruby -v
ruby 1.9.2p0 (2010-08-18 revision 29036) [x86_64-linux]
% rails -v
Rails 3.0.0
% rails new foo -O -m http://datamapper.org/templates/rails.rb
% cd foo
# つぎのdb:setupで怒られるので、ここでGemfileにactiveresourceを追加する。(これも問題?)
% bundle install
% rake db:setup
(in /home/yoshuki/trials/foo)
[datamapper] Created database 'foo_development.db'
[datamapper] Created database 'foo_test.db'
[datamapper] Finished auto_migrate! for :default repository 'foo_development.db'
% ls db
seeds.rb # dbファイルがない
% rails g scaffold Post title:string body:text
% rake db:autoupgrade
(in /home/yoshuki/trials/foo)
[datamapper] Finished auto_upgrade! for :default repository 'foo_development.db'
% ls db
seeds.rb # まだdbファイルがない
この状態でサーバ立ち上げてアクセスしてもテーブルがないと怒られてしまいます。
またdatabase.ymlはリスト1のようになっています。(コメントは省略)
・リスト1(config/database.yml)
defaults: &defaults
adapter: sqlite
development:
database: foo_development.db
<<: *defaults
test:
database: foo_test.db
<<: *defaults
production:
database: foo_production.db
<<: *defaults
そこでソースを漁ったところ、これらを実際に使っているのはリスト2でした。
・リスト2(dm-do-adapter-1.0.2/lib/dm-do-adapter/adapter.rb)
215 DataObjects::URI.new(
216 @options[:adapter],
217 @options[:user] || @options[:username],
218 @options[:password],
219 @options[:host],
220 port,
221 @options[:path] || @options[:database],
222 query,
223 @options[:fragment]
224 ).freeze
221行目でpathがなければdatabaseを使うようになっています。いまはリスト1のようにpathがなくdatabaseのみがある状態なので、これで問題ないように見えます。
そして、つぎにこの@optionsを辿っていくと、リスト3に着きました。
・リスト3(dm-sqlite-adapter-1.0.2/lib/dm-sqlite-adapter/adapter.rb)
19 def normalize_options(options)
20 # TODO Once do_sqlite3 accepts both a Pathname or a String,
21 # normalizing database and path won't be necessary anymore
22 db = (options[:database] || options.delete('database')).to_s
23 path = (options[:path ] || options.delete('path')).to_s
24
25 options.update(:adapter => 'sqlite3', :database => db, :path => path)
26 end
22行目と23行目でキーをシンボルに統一しているようです。dbにはリスト1の設定値がそのまま入るのですがpathは設定していないので・・・はい、ここが原因でした。キーに:pathも’path’もなかった場合には
path = (nil).to_s #=> ""
となってしまいリスト2の221行目でpathがtrueになるため、結果としてdatabaseが無視されます。そしてtrueになったpathも空っぽなので、ファイルが作られないのでした。ここでpathが""ならnilに入れ替えておけばちゃんと作られるようになります。
ただ、いまのDataMapperのテンプレートだとRAILS_ROOT直下にファイルが作られてしまうので、デフォルトのテンプレートのようにディレクトリを付けておきましょう。
database: foo_development.db
↓
database: db/foo_development.db