読者です 読者をやめる 読者になる 読者になる

おもしろwebサービス開発日記

Ruby や Rails を中心に、web技術について書いています

railsのfixture作成を簡単にする方法

(2008/09/12修正)
railsでテストをするときに、fixtureの定義をしなくてはならないことが多々あります。
テーブルが少ないときは手で一つずつ書いていってもいいのですが、テーブルが多いととても大変です。そこで簡単にfixtureを作る方法はないものか調べてみました。


ヽ( ・∀・)ノくまくまー(2006-02-11)


上記の記事に書いてあるように、RAILS_ENVのDBデータをfixtureに変換してあげると楽にfixtureが作れそうです。*1

記事の通りpluginをインストールしてみようかなと思ったら、pluginはgemに統合されたみたいです。まずはインストール。

sudo gem install ar_fixtures

これですぐ使える!と思いきやそうでもないみたい。ドキュメントもしっかり書かれていないっぽいので類推しつつ使えるようにしてゆきました。まずrakeファイルがあるのでコピー

cp /Library/Ruby/Gems/1.8/gems/ar_fixtures-0.0.4/tasks/ar_fixtures.rake RAILS_ROOT/lib/tasks

次にar_fixtures.rakeを編集します。

emacs RAILS_ROOT/lib/tasks/ar_fixtures.rake

一行目、二行目に下記を追加。これでひとまず動くようになります。

require "ActiveRecord"
require "ar_fixtures"

使い方はこんなふうにします。

rake db:fixtures:dump MODEL=modelname

でもこれだと複数のテーブルをfixtureに変換することができません。そこで、ar_fixtures.rakeを下記のように編集しました。

require "ActiveRecord"
require "ar_fixtures"

def env_or_raise(var_name, human_name)
  if ENV[var_name].blank?
    raise "No #{var_name} value given. Set #{var_name}=#{human_name}"
  else
    return ENV[var_name]
  end  
end

def model_or_raise
  return env_or_raise('MODEL', 'ModelName')
end

def limit_or_nil_string
  ENV['LIMIT'].blank? ? 'nil' : ENV['LIMIT']
end

namespace :db do
  namespace :fixtures do
    desc "Dump data to the test/fixtures/ directory. Use MODEL=ModelName and LIMIT (optional)"
    task :dump => :environment do
      eval "#{model_or_raise}.to_fixture(#{limit_or_nil_string})"

    end
    
    namespace :dump do
      desc "Dump all data to the test/fixtures/ directory. "      
      task :all => :environment do
        Dir["app/models/*.rb"].each{|i| eval File.basename(i, '.rb').classify}
        Object.subclasses_of(ActiveRecord::Base).each{|klass| klass.to_fixture rescue p klass.name}
      end
    end
  end
    
  namespace :data do
    desc "Dump data to the db/ directory. Use MODEL=ModelName and LIMIT (optional)"
    task :dump => :environment do
      eval "#{model_or_raise}.dump_to_file(nil, #{limit_or_nil_string})"
      puts "#{model_or_raise} has been dumped to the db folder."
    end

    desc "Load data from the db/ directory. Use MODEL=ModelName"
    task :load => :environment do
      eval "#{model_or_raise}.load_from_file"
    end
  end
end

これで下記のようにすると全てのテーブルがtest/fixtures配下にyamlとして保存されます。

rake db:fixtures:dump:all

rspec使いの人はar_fixtures/lib/ar_fixtures-0.0.4.rbをs/test\/fixtures/spec\/fixtures/gすればOKです。

これで少しテストが楽になりました。でも、もっとうまい方法がありそう。心当たりのある方は教えていただけると嬉しいです。

*1:でもこれが有効に使えるためには登録系のロジックが全部出来上がっている必要がありますね。