id:elm200さんの「データベースからテストフィクスチャを抽出する(to_yaml 不使用)」をさらに改良した
http://d.hatena.ne.jp/elm200/20070928/1190947947
生データからfixtureを作りたいけど、to_yamlとか使うと変なのが出ていやだ、という話。
ありがたく使わせていただいたんだけど、2つほど気になったことがあるので、修正してトラバを送らせていただく。
修正したのは次の2点。
- データ内に改行が入る場合、エラーになってしまう。
- idカラムを含まないテーブルの場合、エラーになってしまう。(多対多テーブルで
:id => false
にしているテーブルがいくつかあるんだ)
というわけで、次のように修正:
- 改行が入る場合は、YAMLの複数行リテラルの記法を用いるようにした
- idは並び替えに使っているだけなので、無ければ順番については妥協する
出力はこんな感じになる。
entry1: id: 1 title: | これは改行を 含むデータだよ body: MyText1 entry2: id: 2 title: MyString2 body: MyText2
コード。
# lib/tasks/fixture_dump.rake def fixture_entry(table_name, obj) res = [] klass = table_name.singularize.camelize.constantize res << "#{ table_name.singularize}#{obj['id']}:" klass.columns.each do |column| name = column.name value = obj[column.name] if value.is_a? String and value =~ /\n/ res << " #{name}: |\n " + value.split("\n").join("\n ") else res << " #{name}: #{value}" end end res.join("\n") end namespace :db do fixtures_dir = "#{RAILS_ROOT}/tmp/fixtures/" namespace :fixtures do desc "Extract database data to the tmp/fixtures/ directory. Use FIXTURES=table_name[,table_name...] to specify table names to extract. " task :dump => :environment do sql = "SELECT * FROM %s ORDER BY id" sql_no_id = "SELECT * FROM %s" skip_tables = ["schema_info"] ActiveRecord::Base.establish_connection FileUtils.mkdir_p(fixtures_dir) if ENV['FIXTURES'] table_names = ENV['FIXTURES'].split(/,/) else table_names = (ActiveRecord::Base.connection.tables - skip_tables) end table_names.each do |table_name| File.open("#{fixtures_dir}#{table_name}.yml", "w") do |file| begin objects = ActiveRecord::Base.connection.select_all(sql % table_name) rescue objects = ActiveRecord::Base.connection.select_all(sql_no_id % table_name) end objects.each do |obj| file.write fixture_entry(table_name, obj) + "\n\n" end end end end end end
使い方は、データが保存されている状況で、
$ rake db:fixtuers:dump
これによって、tmp/fixtures
にデータが保存される。これらをspec/fixtuers
(もちろんRSpec on Railsは使ってるよね:-)に移動して、
$ rake spec:db:fixtures:load
で何事もなく終了すればOK.
Enjoy Testing!