2012/06/29

[rails] ストアドファンクションをロードするrakeタスク

Railsアプリの開発環境下でMySQLのストアドファンクションを作成し、 rakeでロードできるようにしています。
おおよそ次の手順で実現しました。

ストアドファンクションを書く。

{Rails.root}/script/db/sql 配下に、拡張子sqlのファイルとして、 ストアドファンクションを作成。

rakeタスクを書く。

{Rails.root}/lib/task 配下に、db_functions.rakeを作成。
タスクは、

  • db:functions
  • db:functions:load
の2つ。
1つ目は、ロードするファンクションの一覧を表示するタスク。
2つ目は、実際にファンクションをロードするタスク。
内容は以下の通り。
namespace :db do
  namespace :functions do
    desc "List .sql files."
    task :list => :environment do
      path = Rails.root + "script/db/sql/*.sql"
      Dir.glob(path) do |sql|
        puts File.basename(sql)
      end
    end

    desc "Load stored functions to the database."
    task :load => :environment do
      begin
        cmd = build_load_cmd(ActiveRecord::Base.configurations)
        path = Rails.root + "script/db/sql/*.sql"
        Dir.glob(path) do |file|
          exec(cmd + " < " + file)
        end
      rescue => e
        puts e.message
        raise e
      end
    end
  end
end

def build_load_cmd(db_config)
  env = ENV['RAILS_ENV']
  env = 'development' if env.nil?

  conf = db_config[env]
  cmd = "mysql"
  cmd << " -h " + conf["host"]     if conf["host"]
  cmd << " -u " + conf["username"] if conf["username"]
  cmd << " -p"  + conf["password"] if conf["password"]
  cmd << " "    + conf["database"]
  cmd
end

これで、rake db:functions:load とすると、ファンクションが生成されます。
もちろん、sqlファイル内で、drop functionしてからcreate functionしています。

デプロイにCapistranoを使う場合、deploy:migrateタスクのafterフックにdb:functions:loadを追加すれば、 DBに変更がある場合に、ファンクションの更新も漏れ無く実行されます。

0 件のコメント: