Rails 5.1を前提とします。
やりたいこと
次のようなDBスキーマがあるとします。
schema.rbの抜粋
create_table "categories", force: :cascade do |t|
# ...
end
create_table "products", force: :cascade do |t|
# ...
end
create_table "sub_products", force: :cascade do |t|
# ...
end
create_table "category_products", force: :cascade do |t|
t.bigint "category_id"
t.bigint "product_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["category_id", "product_id"], unique: true
t.index ["product_id"]
end
# ...
add_foreign_key "category_products", "categories"
add_foreign_key "category_products", "products"
このときに、category_products
の複合ユニークインデックス [:category_id, :product_id]
を [:category_id, :sub_product_id]
に変更するマイグレーションを作りたい場合を考えます。
ここで、マイグレーションはリバーシブル(マイグレーションを up
, down
したときに正しく前後のDBスキーマに変更できること)になるように気をつけます。
やりかた
change_table
を使って、次のようなマイグレーションを作ります。
class ChangeReferenceInCategoryProducts < ActiveRecord::Migration[5.1]
def change
change_table :category_products do |t|
t.remove_index column: [:category_id, :product_id], unique: true
t.remove_references :product, foreign_key: true
t.references :sub_product, foreign_key: true
t.index [:category_id, :sub_product_id], unique: true
end
end
end
まず、remove_index
で複合ユニークインデックスを削除します。このときに unique: true
を指定しておかないと、db:migrate:down
時に、この複合インデックスをユニーク制約が付いた状態で復元できません。
その後、remove_references
で外部キーカラム product_id
を削除します。
この後は新しい外部キーカラムと複合ユニークインデックスを作ります。削除とは逆に、カラム作成→複合インデックス作成の順番で実行しており、マイグレーション全体として処理が対称になります。
以上の方法で、db:migrate
の up
, down
を行き来できるようになります。