Railsアプリの開発環境下でMySQLのストアドファンクションを作成し、
rakeでロードできるようにしています。
おおよそ次の手順で実現しました。
ストアドファンクションを書く。
{Rails.root}/script/db/sql 配下に、拡張子sqlのファイルとして、 ストアドファンクションを作成。
rakeタスクを書く。
{Rails.root}/lib/task 配下に、db_functions.rakeを作成。
タスクは、
- db:functions
- db:functions:load
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に変更がある場合に、ファンクションの更新も漏れ無く実行されます。