🐙

【Rails】rename_tableするときはrename_columnも必要な場合がある

2024/06/25に公開

結論

rename_tableするときは外部キーの関連でrename_columnも必要な場合がある。

詳細

例えば、少々強引だけどUserモデルを定義すべきところをUserrとタイポして作ったとき。Userr has_many Bookという関連があるとする。
この場合、当然Bookモデルにはuserr_idという外部キーを保存するカラムがある。

ActiveRecord::Schema[7.1].define(version: 2024_06_25_103655) do
  create_table "books", force: :cascade do |t|
    t.string "title", null: false
    t.integer "userr_id", null: false #外部キーもタイポされてる
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["userr_id"], name: "index_books_on_userr_id"
  end

  create_table "userrs", force: :cascade do |t|
    t.string "name", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_foreign_key "books", "userrs"
end

このままではまずいので、rename_tableメソッドを使い、userrs->usersへテーブル名を変更する。

class RenameTable < ActiveRecord::Migration[7.1]
  def change
    rename_table :userrs, :users
  end
end

実行後、テーブル名はusersに変更されたが、Book#userr_id外部キーは修正されていない。

ActiveRecord::Schema[7.1].define(version: 2024_06_25_103838) do
  create_table "books", force: :cascade do |t|
    t.string "title", null: false
    t.integer "userr_id", null: false # 外部キーはまだuserrのまま
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["userr_id"], name: "index_books_on_userr_id" # indexもまだuserrのまま
  end

  create_table "users", force: :cascade do |t|
    t.string "name", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_foreign_key "books", "users", column: "userr_id"
end

よって、rename_columnメソッドも実行する。こうすることで、カラム名とインデックス名が修正される。

class RenameTable < ActiveRecord::Migration[7.1]
  def change
    rename_table :userrs, :users
    rename_column :books, :userr_id, :user_id #userr_idからuser_idへリネーム
  end
end

スキーマを見ると、

  • Book#userr_id->Book#user_id
  • "index_books_on_userr_id"->"index_books_on_user_id"

に変更されているのがわかる。

ActiveRecord::Schema[7.1].define(version: 2024_06_25_103838) do
  create_table "books", force: :cascade do |t|
    t.string "title", null: false
    t.integer "user_id", null: false #リネームされてる
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
    t.index ["user_id"], name: "index_books_on_user_id" #こちらも修正されている
  end

  create_table "users", force: :cascade do |t|
    t.string "name", null: false
    t.datetime "created_at", null: false
    t.datetime "updated_at", null: false
  end

  add_foreign_key "books", "users"
end

インデックス名を変更するのにrename_indexというメソッドもあるが、これはインデックス名のみを変える。だから今回の例のように、カラム名の変更も必要な場合はrename_columnを使うとよい。
ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter

Discussion