ฉันจะเปลี่ยนชื่อคอลัมน์ฐานข้อมูลในการโยกย้าย Ruby on Rails ได้อย่างไร


1451

ฉันผิดชื่อคอลัมน์แทนhased_passwordhashed_password

ฉันจะอัพเดตสกีมาฐานข้อมูลโดยใช้การโอนย้ายเพื่อเปลี่ยนชื่อคอลัมน์นี้ได้อย่างไร

คำตอบ:


2308
rename_column :table, :old_column, :new_column

คุณอาจต้องการสร้างการย้ายข้อมูลแยกต่างหากเพื่อทำสิ่งนี้ (เปลี่ยนชื่อFixColumnNameตามที่คุณต้องการ):

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

จากนั้นแก้ไขการโยกย้ายเพื่อทำตามความประสงค์ของคุณ:

# 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

สำหรับ Rails 3.1 ให้ใช้:

ในขณะที่วิธีการupและdownวิธีการยังคงใช้อยู่ Rails 3.1 ได้รับchangeวิธีการที่ "รู้วิธีโยกย้ายฐานข้อมูลของคุณและย้อนกลับเมื่อการโยกย้ายถูกย้อนกลับโดยไม่จำเป็นต้องเขียนวิธีการแยกลง"

ดู " การโยกย้ายบันทึกที่ใช้งาน " สำหรับข้อมูลเพิ่มเติม

rails g migration FixColumnName

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

หากคุณมีทั้งกลุ่มของคอลัมน์ที่จะเปลี่ยนชื่อหรือสิ่งที่จะต้องทำซ้ำชื่อตารางซ้ำแล้วซ้ำอีก:

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

คุณสามารถใช้change_tableเพื่อรักษาสิ่งที่ neater เล็กน้อย:

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

จากนั้นก็db:migrateเป็นเรื่องปกติหรือเรื่องเกี่ยวกับธุรกิจของคุณ


สำหรับ Rails 4:

ในขณะที่สร้างMigrationสำหรับการเปลี่ยนชื่อคอลัมน์ Rails 4 สร้างchangeวิธีการแทนupและdownตามที่กล่าวไว้ในส่วนด้านบน changeวิธีการสร้างคือ:

$ > rails g migration ChangeColumnName

ซึ่งจะสร้างไฟล์การโยกย้ายคล้ายกับ:

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

24
self.down ควรเสมอจะเป็นตรงข้ามของ self.up ดังนั้น "ถ้าคุณต้องการหรือทำอย่างอื่นหรือไม่ทำอะไรเลย" ไม่แนะนำจริงๆ เพิ่งทำ: rename_column: table_name,: new_column,: old_column
ลุคกริฟฟิ ธ ส์

3
ในขณะที่มันปฏิบัติตามปกติที่จะเปลี่ยนสิ่งที่คุณทำในself.upฉันจะไม่พูดself.down"ควรเสมอจะตรงข้าม" ขึ้นอยู่กับบริบทของการย้ายถิ่นของคุณ เพียงวาง "ตรงกันข้าม" อาจไม่ใช่การโยกย้ายแบบ "ขวา"
nowk

23
ใน Rails 3.1 คุณสามารถแทนที่def self.upและdef self.downมีdef changeและมันจะรู้วิธีที่จะย้อนกลับ
Turadg

2
Turadg - * มันจะรู้วิธีการย้อนเวลาส่วนใหญ่ ฉันพบว่าchangeวิธีการดังกล่าวไม่ได้มีการพิสูจน์อย่างสมบูรณ์ดังนั้นจึงมีแนวโน้มที่จะใช้upและdownวิธีการสำหรับการย้ายที่ซับซ้อน
JellyFishBoy

6
การเปลี่ยนชื่อลบดัชนีหรือไม่
Sung Cho

68

ในความคิดของฉันในกรณีนี้มันจะดีกว่าที่จะใช้แล้วแก้ไขการย้ายถิ่นของคุณและทำงานอีกครั้งrake db:rollbackrake db:migrate

rename_columnแต่ถ้าคุณมีข้อมูลในคอลัมน์ที่คุณไม่ต้องการที่จะสูญเสียแล้วการใช้งาน


34
แม้ใน "ทีมหนึ่ง" หากคุณมีแอปของคุณหลายอินสแตนซ์ทำงานอยู่พูดในสภาพแวดล้อมที่แตกต่างกันหรือในคอมพิวเตอร์หลายเครื่อง ฯลฯ การจัดการการย้ายข้อมูลที่แก้ไขแล้วนั้นเป็นปัญหาที่สำคัญ ฉันเพียงแก้ไขการย้ายข้อมูลหากฉันเพิ่งสร้างขึ้นมาและตระหนักว่ามันผิดและยังไม่ได้เรียกใช้งานจากที่อื่นเลย
Yetanotherjosh

1
ฉันต้องรีสตาร์ทเซิร์ฟเวอร์หลังจากนั้น
Muhammad Hewedy

7
ควรใช้เทคนิคนี้เฉพาะในสถานการณ์ที่การเปลี่ยนแปลงของคุณยังไม่ถูกรวมเข้ากับสาขาการผลิตของคุณและอื่น ๆ ไม่ได้ขึ้นอยู่กับการคงอยู่ของข้อมูล ในทุกกรณีการผลิตนี่ไม่ใช่วิธีการที่ต้องการ
Collin Graves

4
ไม่เคยทำสิ่งนี้เลย
new2cpp

4
ฉันชอบพูดกับทีมของฉันว่า: 'การโยกย้ายไม่เสียค่าใช้จ่าย' ค่าใช้จ่ายในการแก้ไขการโยกย้ายที่ปล่อยสู่ป่านั้นสูง: เมื่อฉันใช้เวลาสองสามชั่วโมงในการหาสาเหตุที่รหัสของฉันไม่ทำงาน ได้ย้อนกลับไปและแก้ไขการย้ายข้อมูลที่ฉันได้ทำงานไปแล้ว ดังนั้นอย่าแก้ไขการย้ายข้อมูลที่มีอยู่ใช้รายการใหม่เพื่อเปลี่ยนสคีมาเนื่องจาก ... ... 'การย้ายข้อมูลฟรี!' (มันไม่เป็นความจริงอย่างเคร่งครัด แต่มันทำให้ประเด็น)
TerryS

31

หากคอลัมน์นั้นมีข้อมูลและใช้งานจริงแล้วฉันขอแนะนำวิธีการทีละขั้นตอนเพื่อหลีกเลี่ยงการหยุดทำงานของการผลิตในขณะที่รอการย้ายข้อมูล

ก่อนอื่นฉันจะสร้างการย้ายฐานข้อมูลเพื่อเพิ่มคอลัมน์ด้วยชื่อใหม่และเติมด้วยค่าจากชื่อคอลัมน์เก่า

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

จากนั้นฉันจะยอมรับการเปลี่ยนแปลงนั้นและผลักดันการเปลี่ยนแปลงไปสู่การผลิต

git commit -m 'adding columns with correct name'

จากนั้นเมื่อความมุ่งมั่นถูกผลักดันไปสู่การผลิตฉันก็จะวิ่ง

Production $ bundle exec rake db:migrate

จากนั้นฉันจะอัปเดตมุมมอง / ตัวควบคุมทั้งหมดที่อ้างอิงชื่อคอลัมน์เก่าเป็นชื่อคอลัมน์ใหม่ ทำงานผ่านชุดทดสอบของฉันและยอมรับการเปลี่ยนแปลงเหล่านั้น (หลังจากทำให้แน่ใจว่ามันทำงานในพื้นที่และผ่านการทดสอบทั้งหมดก่อน!)

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

จากนั้นฉันจะผลักดันสิ่งนั้นให้กับการผลิต

ณ จุดนี้คุณสามารถลบคอลัมน์เดิมโดยไม่ต้องกังวลเกี่ยวกับการหยุดทำงานใด ๆ ที่เกี่ยวข้องกับการย้ายข้อมูลเอง

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

จากนั้นผลักดันการโยกย้ายล่าสุดนี้ไปยังการผลิตและทำงานbundle exec rake db:migrateในพื้นหลัง

ฉันรู้ว่านี่เป็นกระบวนการที่เกี่ยวข้องอีกเล็กน้อย แต่ฉันอยากทำมากกว่าที่จะมีปัญหากับการโยกย้ายการผลิตของฉัน


2
ฉันชอบความคิดที่อยู่เบื้องหลังนี้และฉันจะ +1 repsonse ของคุณ แต่การอัปเดตข้อมูลจะใช้เวลานานมากในการดำเนินการเนื่องจากจะผ่านทางรถไฟและทำทีละหนึ่งแถว การโยกย้ายจะดำเนินการเร็วขึ้นมากด้วยคำสั่ง sql raw เพื่ออัปเดตคอลัมน์ที่มีชื่ออย่างถูกต้อง ตัวอย่างเช่นในสคริปต์การย้ายข้อมูล db แรกหลังจากเพิ่มชื่อคอลัมน์ที่ซ้ำกัน execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann

1
@ mr.ruh.roh ^ เห็นด้วยทั้งหมดควรเขียนว่าในตอนแรก ฉันแก้ไขเพื่อให้สะท้อนถึงคำสั่ง sql ที่มีประสิทธิภาพเดียว ขอบคุณสำหรับการตรวจสุขภาพ
Paul Pettengill

2
เกิดอะไรขึ้นกับรายการระหว่างย้ายไปยังตารางใหม่และอัปเดตรหัสเพื่อใช้ตารางใหม่ คุณไม่สามารถเก็บข้อมูลที่ไม่มีการจัดเก็บข้อมูลไว้ได้หรือไม่?
Stefan Dorunga

1
ในขณะที่นี่คือคำตอบที่ 'ปลอดภัย' ฉันรู้สึกว่ามันไม่สมบูรณ์ หลายคนที่นี่บอกว่าอย่าทำอย่างนี้ทำไม การคงอยู่ของข้อมูล และนั่นก็ใช้ได้ อาจเป็นวิธีที่เจ็บปวดน้อยที่สุดในการบรรลุเป้าหมายคือการสร้างเขตข้อมูลใหม่เติมด้วยข้อมูลจากคอลัมน์เก่าปรับตัวควบคุม หากคุณต้องการลบคอลัมน์เก่าคุณจะต้องแก้ไขมุมมองอย่างแน่นอน ค่าใช้จ่ายในการรักษาคือพื้นที่ db เพิ่มเติมและความพยายามซ้ำซ้อนในคอนโทรลเลอร์ การแลกเปลี่ยนมีความชัดเจน
เจอโรม


18

เรียกใช้คำสั่งด้านล่างเพื่อสร้างไฟล์การโยกย้าย:

rails g migration ChangeHasedPasswordToHashedPassword

จากนั้นในไฟล์ที่สร้างในdb/migrateโฟลเดอร์ให้เขียนrename_columnดังนี้:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end

14

จาก API:

rename_column(table_name, column_name, new_column_name)

มันเปลี่ยนชื่อคอลัมน์ แต่เก็บประเภทและเนื้อหายังคงเหมือนเดิม


12

Ruby on Rails บางเวอร์ชันรองรับวิธีการขึ้น / ลงเพื่อการย้ายข้อมูลและหากคุณมีวิธีการขึ้น / ลงในการย้ายข้อมูลของคุณ:

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

หากคุณมีchangeวิธีในการโยกย้ายของคุณแล้ว:

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

สำหรับข้อมูลเพิ่มเติมคุณสามารถย้าย: Ruby on Rails - โยกย้ายหรือใช้งาน Migrations


11

หากรหัสของคุณไม่ได้ใช้ร่วมกันกับคนอื่น ๆ แล้วเลือกที่ดีที่สุดคือการไม่เพียงแค่นั้นแก้ไขชื่อคอลัมน์ของคุณในการย้ายถิ่นและrake db:rollback rake db:migrateแค่นั้นแหละ

และคุณสามารถเขียนการย้ายข้อมูลอื่นเพื่อเปลี่ยนชื่อคอลัมน์

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

แค่นั้นแหละ.


rake db:rollbackเป็นข้อเสนอแนะที่ดี แต่อย่างที่คุณพูดก็ต่อเมื่อยังไม่ได้ทำการโยกย้าย
danielricecodes

9

เป็นอีกทางเลือกหนึ่งหากคุณยังไม่ได้แต่งงานกับแนวคิดเรื่องการย้ายข้อมูลจะมีอัญมณีที่น่าสนใจสำหรับ ActiveRecord ซึ่งจะจัดการการเปลี่ยนชื่อโดยอัตโนมัติสไตล์ Datamapper สิ่งที่คุณทำคือเปลี่ยนชื่อคอลัมน์ในแบบจำลองของคุณ (และให้แน่ใจว่าคุณใส่Model.auto_upgrade!ที่ด้านล่างของ model.rb ของคุณ) และวิโอลา! ฐานข้อมูลอัพเดทได้ทันที

https://github.com/DAddYE/mini_record

หมายเหตุ: คุณจะต้อง nuke db / schema.rbเพื่อป้องกันความขัดแย้ง

ยังอยู่ในช่วงเบต้าและไม่ชัดเจนสำหรับทุกคน แต่ก็ยังเป็นตัวเลือกที่น่าสนใจ (ขณะนี้ฉันกำลังใช้งานอยู่ในสองแอพพลิเคชั่นที่ไม่สำคัญโดยไม่มีปัญหา)


8

หากคุณต้องการที่จะเปลี่ยนชื่อคอลัมน์ที่คุณจะต้องสร้างตัวยึดเพื่อหลีกเลี่ยงข้อผิดพลาดชื่อคอลัมน์ที่ซ้ำกัน นี่คือตัวอย่าง:

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

7

หากข้อมูลปัจจุบันไม่สำคัญสำหรับคุณคุณสามารถยกเลิกการย้ายข้อมูลดั้งเดิมโดยใช้:

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

หากไม่มีเครื่องหมายอัญประกาศให้ทำการเปลี่ยนแปลงในการย้ายข้อมูลดั้งเดิมและเรียกใช้การโยกย้ายขึ้นอีกครั้งโดย:

rake db:migrate

6

เพียงสร้างการย้ายข้อมูลใหม่และในบล็อกให้ใช้rename_columnดังต่อไปนี้

rename_column :your_table_name, :hased_password, :hashed_password


5

ด้วยตนเองเราสามารถใช้วิธีการด้านล่าง:

เราสามารถแก้ไขการย้ายข้อมูลด้วยตนเองเช่น:

  • เปิด app/db/migrate/xxxxxxxxx_migration_file.rb

  • อัปเดตhased_passwordเป็นhashed_password

  • เรียกใช้คำสั่งด้านล่าง

    $> rake db:migrate:down VERSION=xxxxxxxxx

จากนั้นจะลบการย้ายข้อมูลของคุณ:

$> rake db:migrate:up VERSION=xxxxxxxxx

มันจะเพิ่มการย้ายข้อมูลของคุณพร้อมกับการเปลี่ยนแปลงที่อัปเดต


จะไม่ปลอดภัยเนื่องจากคุณอาจสูญเสียข้อมูล - หากคอลัมน์นั้นเผยแพร่อยู่ แต่สามารถทำได้สำหรับคอลัมน์และ / หรือตารางใหม่
Tejas Patel

5

สร้างไฟล์การโยกย้าย:

rails g migration FixName

# สร้าง db / migrate / xxxxxxxxxx.rb

แก้ไขการโยกย้ายเพื่อทำตามความต้องการของคุณ

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

5

เรียกใช้rails g migration ChangesNameInUsers(หรือสิ่งที่คุณต้องการตั้งชื่อ)

เปิดไฟล์การโยกย้ายที่เพิ่งสร้างขึ้นและเพิ่มบรรทัดนี้ในเมธอด (ระหว่างdef changeและend):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

บันทึกไฟล์และเรียกใช้rake db:migrateในคอนโซล

ลองใช้งานของคุณschema.dbเพื่อดูว่ามีการเปลี่ยนแปลงชื่อจริง ๆ ในฐานข้อมูลหรือไม่!

หวังว่าจะช่วย :)


5

จูบกันเถอะ ทั้งหมดนี้ใช้เวลาเพียงสามขั้นตอน ผลงานต่อไปนี้สำหรับRails 5.2

1. สร้างการโยกย้าย

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- ด้วยวิธีการที่ชัดเจนอย่างสมบูรณ์เพื่อผู้ดูแลฐานรหัสในภายหลัง (ใช้พหูพจน์สำหรับชื่อตาราง)

2. แก้ไขการโยกย้าย

# I prefer to explicitly write theขึ้นandลงmethods.

# ./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. เรียกใช้การย้ายข้อมูลของคุณ

rake db:migrate

และคุณจะออกไปแข่ง!


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

เปิดไฟล์การโยกย้ายนั้นและแก้ไขไฟล์ดังต่อไปนี้ (อย่าป้อนต้นฉบับของคุณtable_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end


3

สร้างการโยกย้าย Ruby on Rails :

$:> rails g migration Fixcolumnname

ใส่รหัสในไฟล์การโยกย้าย (XXXXXfixcolumnname.rb) :

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


2

คุณมีสองวิธีในการทำสิ่งนี้:

  1. ในประเภทนี้มันจะเรียกใช้รหัสย้อนกลับของมันโดยอัตโนมัติเมื่อย้อนกลับ

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. สำหรับประเภทนี้มันจะรันเมธอด up เมื่อrake db:migrateและรันเมธอด down เมื่อ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

2

ฉันอยู่บนราง 5.2 และพยายามเปลี่ยนชื่อคอลัมน์ในผู้ใช้ที่ประดิษฐ์

rename_columnบิตทำงานสำหรับฉัน แต่เอกพจน์:table_nameโยน "ตารางผู้ใช้ไม่พบข้อผิดพลาด" พหูพจน์ทำงานให้ฉัน

rails g RenameAgentinUser

จากนั้นเปลี่ยนไฟล์การโยกย้ายเป็น:

rename_column :users, :agent?, :agent

ตัวแทนอยู่ที่ไหน เป็นชื่อคอลัมน์เก่า


0

Update - ลูกพี่ลูกน้องที่ใกล้ชิดของ create_table คือ change_table ใช้สำหรับเปลี่ยนตารางที่มีอยู่ มันถูกใช้ในลักษณะคล้ายกันกับ create_table แต่วัตถุที่ให้ผลกับบล็อกรู้เทคนิคมากขึ้น ตัวอย่างเช่น:

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

วิธีนี้มีประสิทธิภาพมากขึ้นถ้าเราใช้วิธีการแก้ไขอื่น ๆ เช่น: ลบ / เพิ่มดัชนี / ลบดัชนี / เพิ่มคอลัมน์เช่นเราสามารถทำได้เพิ่มเติมเช่น:

# 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
#...

0

เพียงแค่สร้างการโยกย้ายโดยใช้คำสั่ง

rails g migration rename_hased_password

หลังจากนั้นแก้ไขการโยกย้ายเพิ่มบรรทัดต่อไปนี้ในวิธีการเปลี่ยนแปลง

rename_column :table, :hased_password, :hashed_password

สิ่งนี้ควรทำเคล็ดลับ


0

การเปลี่ยนการโยกย้าย Rails 5

เช่น:

รูปแบบทางรถไฟ g student student_name: อายุสตริง: จำนวนเต็ม

ถ้าคุณต้องการเปลี่ยนคอลัมน์student_nameเป็นชื่อ

หมายเหตุ: - หากคุณไม่ได้รันrails db: migrate

คุณสามารถทำตามขั้นตอน

Rails d model นักเรียน student_name: อายุสตริง: จำนวนเต็ม

สิ่งนี้จะลบไฟล์การย้ายข้อมูลที่สร้างขึ้นตอนนี้คุณสามารถแก้ไขชื่อคอลัมน์ได้

แบบจำลอง Rails g ชื่อนักเรียน: อายุสตริง: จำนวนเต็ม

หากคุณย้ายข้อมูล (ราง db: โยกย้าย) ตัวเลือกต่อไปนี้เพื่อเปลี่ยนชื่อคอลัมน์

rails g โยกย้าย RemoveStudentNameFromStudent student_name: string

Rails g โยกย้าย AddNameToStudent ชื่อ: สตริง


ไม่ควร: rails g migration RemoveStudentNameFromStudentS student_name:string(นักเรียนเป็นพหูพจน์)?
BKSpurgeon

สิ่งนี้ก็เป็นอันตรายเช่นกันคอลัมน์ไม่ได้ถูกเปลี่ยนชื่อ แต่ถูกลบออกทั้งหมดแล้วอ่านใหม่ จะเกิดอะไรขึ้นกับข้อมูล นี่อาจไม่ใช่สิ่งที่ผู้ใช้ต้องการ
BKSpurgeon
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.