rails3とdmでsqliteのdbファイルができない。

「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
タイトルとURLをコピーしました