Bagaimana saya bisa mengganti nama kolom basis data dalam migrasi Ruby on Rails?

1452

Saya salah menyebutkan kolom, hased_passwordbukan hashed_password.

Bagaimana cara saya memperbarui skema database, menggunakan migrasi untuk mengganti nama kolom ini?

pengguna1994764
sumber

Jawaban:

2309
rename_column :table, :old_column, :new_column

Anda mungkin ingin membuat migrasi terpisah untuk melakukan ini. (Ganti nama FixColumnNamesesuai keinginan Anda.):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Kemudian edit migrasi untuk melakukan keinginan Anda:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

Untuk Rails 3.1 gunakan:

Sementara, updan downmetode masih berlaku, Rails 3.1 menerima changemetode yang "tahu cara memigrasi database Anda dan membalikkannya ketika migrasi dibatalkan tanpa perlu menulis metode turun terpisah".

Lihat " Migrasi Rekaman Aktif " untuk informasi lebih lanjut.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

Jika Anda kebetulan memiliki banyak kolom untuk diganti nama, atau sesuatu yang harus mengulangi nama tabel berulang-ulang:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

Anda bisa menggunakan change_tableuntuk menjaga hal-hal sedikit lebih rapi:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Kemudian db:migrateseperti biasa atau bagaimanapun Anda menjalankan bisnis Anda.


Untuk Rails 4:

Saat membuat Migrationuntuk mengganti nama kolom, Rails 4 menghasilkan changemetode, bukan updan downseperti yang disebutkan di bagian di atas. changeMetode yang dihasilkan adalah:

$ > rails g migration ChangeColumnName

yang akan membuat file migrasi mirip dengan:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
sekarang
sumber
24
self.down harus selalu menjadi kebalikan dari self.up, jadi "jika Anda perlu atau melakukan sesuatu yang lain atau tidak melakukan apa-apa" tidak benar-benar direkomendasikan. Lakukan saja: rename_column: table_name,: new_column,: old_column
Luke Griffiths
3
Sementara itu adalah praktik normal untuk mengembalikan apa yang Anda lakukan di self.upsaya tidak akan mengatakan self.down"harus selalu berlawanan". Masuk tergantung pada konteks migrasi Anda. Hanya menempatkan "lawan" mungkin bukan "kanan" migrasi bawah.
nowk
23
Di Rails 3.1 Anda dapat mengganti def self.updan def self.downdengan def changedan itu akan tahu cara mengembalikan.
Turadg
2
Turadg - * ia akan tahu cara mengembalikan sebagian besar waktu. Saya menemukan changemetode ini bukan bukti lengkap, jadi cenderung menggunakan updan downmetode untuk migrasi kompleks.
JellyFishBoy
6
Apakah mengganti nama menghapus indeks?
Sung Cho
68

Menurut pendapat saya, dalam hal ini, lebih baik digunakan rake db:rollback, lalu edit migrasi Anda dan jalankan kembali rake db:migrate.

Namun, jika Anda memiliki data di kolom yang tidak ingin hilang, gunakan rename_column.

elf.xf
sumber
34
Bahkan di "tim satu", jika Anda memiliki beberapa kejadian aplikasi Anda berjalan, katakanlah di lingkungan yang berbeda atau di beberapa komputer dll, mengelola migrasi yang diedit adalah masalah besar. Saya hanya mengedit migrasi jika saya baru saja membuatnya dan menyadari itu salah, dan belum menjalankannya secara harfiah di tempat lain.
Yetanotherjosh
1
Saya harus me-restart server setelah itu.
Muhammad Hewedy
7
Teknik ini seharusnya hanya digunakan dalam situasi di mana perubahan Anda belum digabung dengan cabang produksi Anda, dan yang lain tidak bergantung pada kegigihan data. Dalam kebanyakan keadaan produksi, ini BUKAN metode yang disukai.
Collin Graves
4
tidak pernah melakukan hal semacam ini.
new2cpp
4
Saya ingin mengatakan kepada tim saya: 'Migrasi gratis' telah kembali dan mengedit migrasi yang sudah saya jalankan. Jadi jangan edit migrasi yang ada, gunakan yang baru untuk mengubah skema, karena ... ... 'Migrasi gratis!' (itu tidak sepenuhnya benar, tetapi itu yang penting)
TerryS
31

Jika kolom sudah diisi dengan data dan hidup dalam produksi, saya akan merekomendasikan pendekatan langkah demi langkah, untuk menghindari downtime dalam produksi sambil menunggu migrasi.

Pertama saya akan membuat migrasi db untuk menambahkan kolom dengan nama baru dan mengisinya dengan nilai-nilai dari nama kolom yang lama.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Lalu saya akan melakukan perubahan itu saja, dan mendorong perubahan ke dalam produksi.

git commit -m 'adding columns with correct name'

Kemudian begitu komit telah didorong ke dalam produksi, saya akan lari.

Production $ bundle exec rake db:migrate

Lalu saya akan memperbarui semua tampilan / pengontrol yang merujuk nama kolom lama ke nama kolom baru. Jalankan melalui test suite saya, dan lakukan hanya perubahan itu. (Setelah memastikan itu berfungsi secara lokal dan melewati semua tes terlebih dahulu!)

git commit -m 'using correct column name instead of old stinky bad column name'

Lalu saya akan mendorong komitmen itu untuk produksi.

Pada titik ini Anda dapat menghapus kolom asli tanpa khawatir tentang segala jenis downtime yang terkait dengan migrasi itu sendiri.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Kemudian dorong migrasi terbaru ini ke produksi dan berjalan bundle exec rake db:migratedi latar belakang.

Saya menyadari ini sedikit lebih terlibat dalam suatu proses, tetapi saya lebih suka melakukan ini daripada memiliki masalah dengan migrasi produksi saya.

Paul Pettengill
sumber
2
Saya suka pemikiran di balik ini, dan saya akan memberi +1 pada perwakilan Anda tetapi pembaruan data akan membutuhkan waktu yang sangat lama untuk dieksekusi karena akan melalui rel dan melakukan satu baris pada satu waktu. Migrasi akan berjalan jauh lebih cepat dengan pernyataan sql mentah untuk memperbarui kolom dengan nama yang benar. Misalnya, dalam skrip migrasi db pertama, setelah menambahkan nama kolom duplikat, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann
1
@ mr.ruh.roh ^ Sepenuhnya setuju, seharusnya menulis itu di tempat pertama. Saya telah mengedit untuk mencerminkan pernyataan sql efisien tunggal. Terima kasih untuk cek kewarasannya.
Paul Pettengill
2
Apa yang terjadi dengan entri di antara pindah ke tabel baru dan memperbarui kode untuk menggunakan tabel baru? Bisakah Anda tidak memiliki data yang berpotensi tidak dimigrasikan yang tersisa?
Stefan Dorunga
1
sementara ini adalah jawaban yang 'aman', saya merasa itu tidak lengkap. Banyak orang di sini mengatakan tidak melakukan ini -mengapa? kegigihan data. Dan itu valid. Mungkin cara yang paling tidak menyakitkan untuk mencapai tujuannya adalah membuat bidang baru, mengisinya dengan data dari kolom lama, menyesuaikan pengontrol. Jika Anda ingin menghapus kolom yang lama, Anda tentu harus mengedit tampilan. Biaya untuk mempertahankannya adalah ruang db ekstra dan beberapa upaya duplikat dalam pengontrol. Pengorbanannya jelas.
Jerome
18

Jalankan perintah di bawah ini untuk membuat file migrasi:

rails g migration ChangeHasedPasswordToHashedPassword

Kemudian pada file yang dihasilkan di db/migratefolder, tulis rename_columnseperti di bawah ini:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end
Shoaib Malik
sumber
14

Dari API:

rename_column(table_name, column_name, new_column_name)

Itu mengubah nama kolom tetapi menjaga jenis dan konten tetap sama.

super_p
sumber
12

Beberapa versi Ruby on Rails mendukung metode naik / turun untuk migrasi dan jika Anda memiliki metode naik / turun dalam migrasi Anda, maka:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

Jika Anda memiliki changemetode dalam migrasi Anda, maka:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

Untuk informasi lebih lanjut, Anda dapat memindahkan: Ruby on Rails - Migrations atau Migrasi Rekaman Aktif .

uma
sumber
11

Jika kode Anda tidak dibagikan dengan yang lain, maka opsi terbaik adalah dengan hanya rake db:rollback mengedit nama kolom Anda dalam migrasi dan rake db:migrate. Itu dia

Dan Anda dapat menulis migrasi lain untuk mengganti nama kolom

 def change
    rename_column :table_name, :old_name, :new_name
  end

Itu dia.

sunil
sumber
rake db:rollbackadalah saran yang bagus. Tapi seperti yang Anda katakan, hanya jika migrasi belum didorong.
danielricecodes
9

Sebagai opsi alternatif, jika Anda belum menikah dengan ide migrasi, ada permata yang menarik untuk ActiveRecord yang akan menangani perubahan nama secara otomatis untuk Anda, gaya Datamapper. Yang Anda lakukan hanyalah mengubah nama kolom pada model Anda (dan pastikan Anda meletakkan Model.auto_upgrade! Di bagian bawah model.rb Anda) dan biola! Database diperbarui dengan cepat.

https://github.com/DAddYE/mini_record

Catatan: Anda perlu nuke db / schema.rb untuk mencegah konflik

Masih dalam fase beta dan jelas bukan untuk semua orang tetapi masih merupakan pilihan yang menarik (saya saat ini menggunakannya dalam dua aplikasi produksi non-sepele tanpa masalah)

Steven Garcia
sumber
8

Jika Anda perlu mengganti nama kolom, Anda harus membuat placeholder untuk menghindari kesalahan nama kolom duplikat . Ini sebuah contoh:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end
Abram
sumber
7

Jika data saat ini tidak penting bagi Anda, Anda bisa menghapus migrasi asli menggunakan:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

Tanpa tanda kutip, lalu buat perubahan dalam migrasi asli dan jalankan migrasi lagi dengan:

rake db:migrate
pengotor kotor
sumber
6

Cukup buat migrasi baru, dan di blok, gunakan rename_columnseperti di bawah ini.

rename_column :your_table_name, :hased_password, :hashed_password
jon snow
sumber
6

Untuk Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end
Hardik Hardiya
sumber
5

Secara manual kita dapat menggunakan metode di bawah ini:

Kami dapat mengedit migrasi secara manual seperti:

  • Buka app/db/migrate/xxxxxxxxx_migration_file.rb

  • Perbarui hased_passwordkehashed_password

  • Jalankan perintah di bawah ini

    $> rake db:migrate:down VERSION=xxxxxxxxx

Maka itu akan menghapus migrasi Anda:

$> rake db:migrate:up VERSION=xxxxxxxxx

Itu akan menambah migrasi Anda dengan perubahan yang diperbarui.

Sumit Munot
sumber
itu tidak akan aman karena Anda mungkin kehilangan data - jika kolom sudah hidup. tetapi bisa dilakukan untuk kolom dan / atau tabel baru.
Tejas Patel
5

Buat file migrasi:

rails g migration FixName

# Membuat db / bermigrasi / xxxxxxxxxx.rb

Edit migrasi untuk melakukan kehendak Anda.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
sumber
5

Lari rails g migration ChangesNameInUsers (atau apa pun yang ingin Anda beri nama)

Buka file migrasi yang baru saja dibuat, dan tambahkan baris ini dalam metode (di antara def changedan end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Simpan file, dan jalankan rake db:migratedi konsol

Periksa Anda schema.dbuntuk melihat apakah nama itu benar-benar telah berubah dalam database!

Semoga ini membantu :)

Maddie
sumber
5

Mari kita Kiss . Yang diperlukan hanyalah tiga langkah sederhana. Berikut ini berfungsi untuk Rails 5.2 .

1. Buat Migrasi

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- dengan begitu sangat jelas bagi pengelola basis kode nanti. (gunakan jamak untuk nama tabel).

2. Edit migrasi

# I prefer to explicitly write thenaik andke bawahmethods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3. Jalankan migrasi Anda

rake db:migrate

Dan Anda pergi ke balapan!

BKSpurgeon
sumber
4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

Buka file migrasi itu dan modifikasi file itu seperti di bawah ini (Masukkan yang asli table_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end
Prabhakar Undurthi
sumber
4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end
Apoorv
sumber
3

Buat migrasi Ruby on Rails :

$:> rails g migration Fixcolumnname

Masukkan kode dalam file migrasi (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end
vipin
sumber
2

Buka konsol Ruby on Rails Anda dan masukkan:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column
rinold simon
sumber
2

Anda memiliki dua cara untuk melakukan ini:

  1. Dalam jenis ini secara otomatis menjalankan kode sebaliknya, ketika rollback.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Untuk jenis ini, ia menjalankan metode naik kapan rake db:migratedan menjalankan metode turun ketika rake db:rollback:

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end
Sarwan Kumar
sumber
2

Saya di kereta 5.2, dan mencoba mengubah nama kolom pada Pengguna yang dirancang.

yang rename_columnsedikit bekerja untuk saya, tapi bentuk tunggal :table_namemelemparkan "meja Pengguna tidak ditemukan" kesalahan. Plural bekerja untuk saya.

rails g RenameAgentinUser

Kemudian ubah file migrasi ke ini:

rename_column :users, :agent?, :agent

Di mana: agen? adalah nama kolom yang lama.

makam
sumber
0

Pembaruan - Sepupu dekat create_table adalah change_table, digunakan untuk mengubah tabel yang ada. Ini digunakan dengan cara yang mirip dengan create_table tetapi objek yang dihasilkan blok tahu lebih banyak trik. Sebagai contoh:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

Cara ini lebih efisien jika kita lakukan dengan metode alter lain seperti: hapus / tambah indeks / hapus indeks / tambahkan kolom, misalnya kita dapat melakukan lebih lanjut seperti:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...
Hieu Pham
sumber
0

Hasilkan migrasi menggunakan perintah saja

rails g migration rename_hased_password

Setelah itu edit migrasi tambahkan baris berikut dalam metode perubahan

rename_column :table, :hased_password, :hashed_password

Ini harus melakukan trik.

Ratnam Yadav
sumber
0

Perubahan migrasi Rails 5

misalnya:

rails g model Student_name student: usia string: integer

jika Anda ingin mengubah kolom student_name sebagai nama

Catatan: - jika Anda tidak menjalankan rails db: migrate

Anda bisa melakukan langkah-langkah berikut

rails d model Student_name student: usia string: integer

Ini akan menghapus file migrasi yang dihasilkan, Sekarang Anda dapat memperbaiki nama kolom Anda

rails g model Nama siswa: usia string: integer

Jika Anda bermigrasi (rails db: migrate), opsi berikut untuk mengubah nama kolom

rails g migrasi RemoveStudentNameFromStudent student_name: string

rel g migrasi AddNameToStudent name: string

ahli prasasti
sumber
Bukankah seharusnya: rails g migration RemoveStudentNameFromStudentS student_name:string(para siswa jamak)?
BKSpurgeon
Ini juga berbahaya: kolom tidak diganti namanya, tetapi dihapus seluruhnya dan kemudian dibaca kembali. Apa yang akan terjadi pada data? Ini mungkin bukan yang diinginkan pengguna.
BKSpurgeon