Rails โยกย้ายสำหรับคอลัมน์การเปลี่ยนแปลง


327

เรามีscript/generate migration add_fieldname_to_tablename fieldname:datatypeไวยากรณ์สำหรับการเพิ่มคอลัมน์ใหม่ให้กับโมเดล

ในบรรทัดเดียวกันเรามีสคริปต์ / สร้างสำหรับการเปลี่ยนประเภทข้อมูลของคอลัมน์หรือไม่? หรือฉันควรเขียน SQL โดยตรงลงในการโยกย้ายวานิลลาของฉัน

ฉันต้องการเปลี่ยนคอลัมน์จากการdatetimedate

คำตอบ:


548

ฉันคิดว่ามันน่าจะใช้ได้นะ

change_column :table_name, :column_name, :date

13
@b_ayan: เท่าที่ฉันรู้คำวิเศษวิเศษเพียงคำเดียวในชื่อการย้ายข้อมูลคือ "เพิ่ม" และ "ลบ"
อเล็กซ์ Korban

1
Sort-of rails noob ที่นี่ แต่ ... ฉันเข้าใจคำตอบ แต่ไม่ใช่ความคิดเห็นของคำตอบนี้ การชี้แจงชื่นชม :)
Alan H.

7
เมื่อคุณสร้างการย้ายข้อมูลคุณให้ชื่อ (เช่น add_fieldname_to_tablename ในคำถามด้านบน) หากเริ่มต้นด้วย "เพิ่ม" หรือ "ลบ" การโยกย้ายจะถูกเติมโดยอัตโนมัติด้วยรหัสเพื่อเพิ่มหรือลบคอลัมน์ซึ่งช่วยให้คุณเขียนรหัสนั้นด้วยตัวเอง
Alex Korban

6
คุณควรแทนที่การchangeกระทำปกติด้วยการแยกupและdownการกระทำเช่นเดียวกับchange_columnการโยกย้ายที่ไม่สามารถย้อนกลับได้และจะเพิ่มข้อผิดพลาดหากคุณจำเป็นต้องย้อนกลับ
DaveStephens

1
@QPaysTaxes up ควรมีสิ่งที่คุณต้องการเปลี่ยนคอลัมน์จากและเป็น, และ down ควรมีวิธีย้อนกลับการเปลี่ยนแปลงนั้น
DaveStephens

98

คุณยังสามารถใช้บล็อกได้หากคุณมีหลายคอลัมน์ที่จะเปลี่ยนแปลงภายในตาราง

ตัวอย่าง:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

ดูเอกสารประกอบ API บนคลาส Tableสำหรับรายละเอียดเพิ่มเติม


88

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

หาก tablename เป็นชื่อของตารางของคุณ fieldname เป็นชื่อของฟิลด์ของคุณและคุณต้องการเปลี่ยนจากวันที่และเวลาเป็นวันที่คุณสามารถเขียนการย้ายข้อมูลเพื่อทำสิ่งนี้

คุณสามารถสร้างการย้ายข้อมูลใหม่ด้วย:

rails g migration change_data_type_for_fieldname

จากนั้นแก้ไขการโยกย้ายเพื่อใช้ change_table:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

จากนั้นเรียกใช้การย้ายข้อมูล:

rake db:migrate

32

ตามที่ฉันพบโดยคำตอบก่อนหน้านี้มีสามขั้นตอนที่จำเป็นในการเปลี่ยนประเภทของคอลัมน์:

ขั้นตอนที่ 1:

สร้างไฟล์การโยกย้ายใหม่โดยใช้รหัสนี้:

rails g migration sample_name_change_column_type

ขั้นตอนที่ 2:

ไปที่/db/migrateโฟลเดอร์และแก้ไขไฟล์การโยกย้ายที่คุณทำ มีสองวิธีที่แตกต่างกัน

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end

2

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

ขั้นตอนที่ 3:

อย่าลืมที่จะทำคำสั่งนี้:

rake db:migrate

ฉันได้ทดสอบวิธีนี้สำหรับ Rails 4 และใช้งานได้ดี


1
ในขั้นตอนที่ 2 ตัวแรกจะล้มเหลวหลังจากรัน rake db: rollback ฉันขอแนะนำให้คุณตรวจสอบชุดที่สอง
Feuda

มีแบบแผนทางรถไฟที่อนุญาตให้ทุกอย่างทำได้มากหรือน้อยเมื่อสร้างไฟล์การย้ายข้อมูลโดยไม่ต้องไปที่มันแล้วทำการแก้ไขหรือไม่?
BKSpurgeon

@BKSpurgeon ใช่ตรวจสอบเอกสารที่นี่: edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi

12

ด้วย Rails 5

จากคู่มือราง :

หากคุณต้องการให้การโยกย้ายทำสิ่งที่ Active Record ไม่รู้วิธีย้อนกลับคุณสามารถใช้reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end

8

เพียงสร้างการโยกย้าย:

rails g migration change_column_to_new_from_table_name

อัปเดตการโยกย้ายเช่นนี้:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

และในที่สุดก็

rake db:migrate

2

อีกวิธีในการเปลี่ยนประเภทข้อมูลโดยใช้การย้ายข้อมูล

ขั้นที่ 1: คุณต้องลบชื่อเขตข้อมูลชนิดที่มีข้อบกพร่องโดยใช้การย้ายข้อมูล

อดีต:

rails g migration RemoveFieldNameFromTableName field_name:data_type

ที่นี่อย่าลืมระบุประเภทข้อมูลสำหรับเขตข้อมูลของคุณ

ขั้นตอนที่ 2: ตอนนี้คุณสามารถเพิ่มเขตข้อมูลด้วยชนิดข้อมูลที่ถูกต้อง

อดีต:

rails g migration AddFieldNameToTableName field_name:data_type

เพียงเท่านี้ตารางของคุณจะถูกเพิ่มด้วยฟิลด์ประเภทข้อมูลที่ถูกต้องมีความสุขการเข้ารหัสทับทิม !!


2

นี่คือสมมุติว่าประเภทข้อมูลของคอลัมน์มีการแปลงโดยนัยสำหรับข้อมูลใด ๆ ที่มีอยู่ ฉันพบกับสถานการณ์หลายอย่างที่ข้อมูลที่มีอยู่สมมติว่า a Stringสามารถแปลงเป็นประเภทข้อมูลใหม่โดยนัยDateได้

ในสถานการณ์นี้การรู้ว่าคุณสามารถสร้างการย้ายข้อมูลด้วยการแปลงข้อมูลเป็นประโยชน์ โดยส่วนตัวแล้วฉันชอบวางสิ่งเหล่านี้ลงในไฟล์โมเดลแล้วลบออกหลังจากสกีมาฐานข้อมูลทั้งหมดได้รับการโยกย้ายและมีเสถียรภาพ

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end

0

หากต้องการคำตอบที่สมบูรณ์ในกรณีที่แก้ไขค่าเริ่มต้น :

ในคอนโซลทางรถไฟของคุณ:

rails g migration MigrationName

ในการย้ายถิ่น:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

จะมีลักษณะ:

  def change
    change_column :members, :approved, :boolean, default: true
  end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.