Ridgepoleを使っていると、たまによく分からない差分が出てくることがあります。
そういうときにverboseオプションをつけて実行すると、内部でどのような比較を行っているのかが出力されるので、デバッグの助けになります。
例えば次のようなSchemafileがあったとして
create_table "users", force: :cascade do |t| t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index "lower(name)" end
一回適用したのに、もう一度適用しようとすると差分(とエラー)が出てくる。
$ ridgepole -a Apply `Schemafile` -- create_table("users", {}) -> 0.0109s -- add_index("users", "lower(name)", {}) -> 0.0054s $ ridgepole -a --dry-run Apply `Schemafile` (dry-run) remove_index("users", {:name=>"index_users_on_lower_name"}) add_index("users", "lower(name)", {}) [ERROR] Index name 'index_users_on_lower_name' on table 'users' already exists 1: remove_index("users", {:name=>"index_users_on_lower_name"}) * 2: add_index("users", "lower(name)", {}) /Users/sugawara/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract/schema_statements.rb:1169:in `add_index_options'
なので--verbose
をつけて実行してみます。
$ ridgepole -a --dry-run --verbose Apply `Schemafile` (dry-run) # Parse DSL # Load tables # users # Compare definitions # users {"created_at"=>{:options=>{:null=>false}, :type=>:datetime}, "name"=>{:options=>{:null=>false}, :type=>:string}, "updated_at"=>{:options=>{:null=>false}, :type=>:datetime}}, - :indices=> - {"index_users_on_lower_name"=> - {:column_name=>"lower((name)::text)", - :options=>{:name=>"index_users_on_lower_name"}}}, + :indices=>{"lower(name)"=>{:column_name=>"lower(name)", :options=>{}}}, :options=>{}} remove_index("users", {:name=>"index_users_on_lower_name"}) add_index("users", "lower(name)", {}) [ERROR] Index name 'index_users_on_lower_name' on table 'users' already exists 1: remove_index("users", {:name=>"index_users_on_lower_name"}) * 2: add_index("users", "lower(name)", {}) /Users/sugawara/.rbenv/versions/2.4.2/lib/ruby/gems/2.4.0/gems/activerecord-5.2.0/lib/active_record/connection_adapters/abstract/schema_statements.rb:1169:in `add_index_options'
紫の部分が変更前、つまり実際のデータベースからエクスポートした情報、水色の部分が変更後、つまりSchemafileをパースした情報です。
差異を見てみると
lower(name)
はlower((name)::text)
として解釈・適用されている- 自動的にインデックス名
index_users_on_lower_name
が付けられている
ということが分かります。
なのでSchemafileを以下のように修正すると差分は出なくなります。
create_table "users", force: :cascade do |t| t.string "name", null: false t.datetime "created_at", null: false t.datetime "updated_at", null: false t.index "lower((name)::text)", name: "index_users_on_lower_name" end
$ ridgepole -a --dry-run Apply `Schemafile` (dry-run) No change
ちなみに、このようなデータベースの暗黙的な変更(例えばMySQLだと外部キーに自動的にインデックスが貼られる件など)をRidgepole側で吸収するのはなかなか難しいので、できるだけデーターベース様の意向に沿ってください…というのが今のところのポリシーです。