Open6
ridgepole が updated_at で差分を出してしまう
t.datetime :updated_at,
null: false, default: -> { 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' }
t.datetime :created_at,
null: false, default: -> { 'CURRENT_TIMESTAMP' }
created_at は問題ないが、 updated_at はダメ
以下は ridgepole の diff.rb で default の Proc を call して文字列に変換している箇所。
上が現在のDBのダンプで下が Schema ファイル。
{:default=>"CURRENT_TIMESTAMP", :null=>false, :unsigned=>false}
{:null=>false, :default=>"CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP", :unsigned=>false}
ON UPDATE 以降が消えている。
+------------+--------------+------+-----+-------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+------------+--------------+------+-----+-------------------+-----------------------------+
| updated_at | datetime | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP |
| created_at | datetime | NO | | CURRENT_TIMESTAMP | |
+------------+--------------+------+-----+-------------------+-----------------------------+
sql からテーブル定義を見ると、 Extra というところに入ってしまっているものが dump されていないのがわかる。
ridgepole は多分、 rails の db:dump の機能を使って現DBから Schema を生成し、 Schemafile と差分検出して適用しているのだと思うが、 db:dump が extra を出してくれないのだと思う。
(rails 標準の migration 機能は db:dump を見ないので問題にはならない)
updated_at の default: -> { 'CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP' } が dump されないので比較ロジックを上書きして無視する
module RidgepoleDiffPatch
def normalize_default_proc_options!(opts1, opts2)
if opts1[:default].is_a?(Proc) && opts2[:default].is_a?(Proc)
opts1[:default] = "#<Proc>" # opts1[:default].call
opts2[:default] = "#<Proc>" # opts2[:default].call
end
end
end
class Ridgepole::Diff
prepend RidgepoleDiffPatch
end
bin/ridgepole
に外からパッチを当てる方法がない。とりあえず必要なのは apply
と dry-run
なので、使うとこだけ適当にコピーして rake task から呼ぶようにした。これで patch を当てられる。
def ridgepole_apply(schemafile_, spec_name, db_name: nil, env: Rails.env, dry_run: false)
schemafile = Rails.root.join("db/schemas/#{schemafile_}")
logger = Ridgepole::Logger.instance
options = { dry_run:, debug: false, color: $stdout.tty? }
# Ridgepole::Config.load は PORTAL_DATABASE_URL による上書きを処理しない
# config = Ridgepole::Config.load('config/database.yml', env, spec_name)
config = ActiveRecord::Base.configurations.configs_for(env_name: env, name: spec_name).configuration_hash
config = config.merge(database: db_name) if db_name
Mysql2::Client.new(config.except(:database)).query("CREATE DATABASE IF NOT EXISTS `#{config[:database]}` CHARACTER SET utf8mb4")
client = Ridgepole::Client.new(config, options)
delta = client.diff(schemafile.read, path: schemafile.to_s)
differ, out = delta.migrate(noop: dry_run)
logger.info('No change') unless differ
puts out if out # rubocop:disable Rails/Output
end