วิธีการเปลี่ยนคอลัมน์ที่ไม่สามารถเปลี่ยนเป็นไม่ได้เป็นโมฆะในการย้ายข้อมูลของ Rails


188

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

คำตอบ:


204

หากคุณทำในการโยกย้ายคุณอาจทำเช่นนี้:

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false

1
เพียงแค่ทราบเพราะสิ่งนี้ทำให้ฉัน bust ฐานข้อมูล dev ของฉัน MyModel.update_all({:date_column => Time.now}, {:date_column => nil})แทนที่จะใช้ไวยากรณ์กัญชาอย่างชัดเจนเช่นนี้ แบบสอบถามในรูปแบบดั้งเดิมของคุณทำให้ทุกรุ่นของฉันมีค่าเป็นศูนย์ในฟิลด์
dimitarvp

ขอบคุณสำหรับการอัพเดท. ฉันรู้ว่านี่ไม่ใช่กรณีเมื่อฉันเขียนคำตอบนี้ แต่ฉันจำไม่ได้ว่า Ruby หรือ RoR รุ่นใดที่ฉันใช้อยู่ในขณะนั้น
DanneManne

1
คุณใช้วิธีการ 'up' / 'down' ในการย้ายข้อมูลนี้หรือคุณสามารถเปลี่ยนวิธีการอย่างง่ายในการย้ายข้อมูล
EE33

2
changeวิธีการที่ไม่เหมาะสำหรับกรณีนี้เพราะ (1) update_allวิธีการที่จะดำเนินการในทั้งโยกย้ายและย้อนกลับที่มีศักยภาพ นั่นอาจไม่ใช่สิ่งที่เลวร้ายที่สุด แต่เนื่องจาก (2) การโยกย้ายไม่มีทางที่จะรู้ได้ว่าคอลัมน์นั้นเปลี่ยนไปจากอะไรในการเปลี่ยนกลับที่เป็นไปได้ ดังนั้นสำหรับกรณีนี้ผมจะติดกับและup down
DanneManne

2
สำหรับผู้ที่สนใจคำตอบของฉันจะแสดงวิธีการในขั้นตอนเดียว
Rick Smith

167

ใน Rails 4 นี่เป็นทางออกที่ดีกว่า (DRYer):

change_column_null :my_models, :date_column, false

เพื่อให้แน่ใจว่าไม่มีระเบียนที่มีNULLค่าในคอลัมน์นั้นคุณสามารถผ่านพารามิเตอร์ตัวที่สี่ซึ่งเป็นค่าเริ่มต้นสำหรับใช้กับระเบียนที่มีNULLค่า:

change_column_null :my_models, :date_column, false, Time.now

4
สิ่งนี้ทำให้เกิดปัญหาเมื่อตารางมีค่า Null อยู่แล้ว ดูคำตอบของฉัน
Rick Smith

5
มีให้ใน 3.2 มีพารามิเตอร์ตัวที่สี่เช่นกันสำหรับการตั้งค่าเริ่มต้นโดยที่ค่าเป็นโมฆะ
toxaq

1
พลัส 1 change_column_nullสำหรับ อย่างไรก็ตามความคิดเห็นของ Rick Smith ด้านบนชี้ให้เห็นกรณีที่ถูกต้องมาก
0112

อัปเดตเพื่อเพิ่มแบบสอบถามเพื่ออัปเดตค่า Null พารามิเตอร์ที่ 4 (ค่าเริ่มต้น) จะมีประโยชน์ก็ต่อเมื่อคุณต้องการให้มีค่าเริ่มต้นสำหรับบันทึกในอนาคตเช่นกัน
mrbrdo

3
อันที่จริงตามเอกสาร 4.2 ของ Rails Param ที่ 4 ไม่ได้ตั้งค่าเริ่มต้นสำหรับบันทึกในอนาคต: "วิธีการยอมรับอาร์กิวเมนต์ตัวที่สี่ที่เป็นตัวเลือกเพื่อแทนที่ + NULL + s ที่มีอยู่ด้วยค่าอื่น ๆ โปรดทราบว่าอาร์กิวเมนต์ที่สี่ไม่ได้ตั้งค่า ค่าเริ่มต้นของคอลัมน์ "
Mike Fischer

70

Rails 4 (Rails 4 คำตอบอื่น ๆ มีปัญหา):

def change
  change_column_null(:users, :admin, false, <put a default value here> )
  # change_column(:users, :admin, :string, :default => "")
end

การเปลี่ยนคอลัมน์ที่มีค่า NULL อยู่ในนั้นไม่อนุญาตให้ NULL ทำให้เกิดปัญหา นี่คือประเภทของรหัสที่จะทำงานได้ดีในการตั้งค่าการพัฒนาของคุณจากนั้นหยุดทำงานเมื่อคุณพยายามปรับใช้กับการผลิตสดของคุณ คุณควรเปลี่ยนค่า NULL ให้เป็นค่าที่ถูกต้องจากนั้นจึงไม่อนุญาต NULL ค่าที่ 4 change_column_nullนั้นทำสิ่งนั้นอย่างแน่นอน ดูเอกสารประกอบสำหรับรายละเอียดเพิ่มเติม

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


3
สำหรับ Rails 4 สิ่งนี้ดูเหมือนจะเป็นคำตอบที่ถูกต้องและครบถ้วนที่สุดรวมถึงการตั้งค่าเริ่มต้นที่แสดงความคิดเห็น
Mike Fischer

4
หากคุณกำลังเพิ่มคอลัมน์ใหม่ลงในตารางและต้องการแทรกค่าใหม่สำหรับค่า null แต่ไม่ต้องการเพิ่มค่าเริ่มต้นสำหรับคอลัมน์คุณสามารถทำได้ในการย้ายข้อมูลของคุณ: add_column :users, :admin, :stringจากนั้นchange_column_null(:admin, :string, false, "new_value_for_existing_records")
colsen

34

สร้างการโยกย้ายที่มีchange_columnคำสั่งที่มี:default =>ค่า

change_column :my_table, :my_column, :integer, :default => 0, :null => false

ดู: change_column

ขึ้นอยู่กับเอ็นจิ้นฐานข้อมูลที่คุณอาจต้องใช้ change_column_null


1
สิ่งนี้ใช้ได้สำหรับฉัน ใช้ MySql ในเครื่อง เมื่อผลักและรันแอพใน Heroku (Postgres) มันวางบนคอลัมน์ที่ไม่เป็นโมฆะเมื่อฉันเขียนมันเป็นโมฆะ - ถูกต้อง เฉพาะ "change_column_null" เท่านั้นที่ไม่สามารถใช้ "change_column ... : null => false" บน MySql ขอบคุณ
rtfminc

1
ดังนั้นการโยกย้ายของคุณคืออะไรหลังจาก change_column_null
js111

1
Postges เป็นที่เข้มงวดมากขึ้นว่า MySQL - change_column_nullฉันคาดหวังว่ามันจะต้องมี
jessecurry

3
@rtfminc ฉันขอแนะนำให้คุณใช้โปรแกรมฐานข้อมูลเดียวกันในการพัฒนาและในการผลิตเพราะมันช่วยหลีกเลี่ยงปัญหามากมายเมื่อพูดถึงกรณีที่เป็นขอบ
yagooar


3

ในRails 4.02+ตามเอกสารไม่มีวิธีใดที่เหมือนกับupdate_all2 อาร์กิวเมนต์ คุณสามารถใช้รหัสนี้แทน:

# Make sure no null value exist
MyModel.where(date_column: nil).update_all(date_column: Time.now)

# Change the column to not allow null
change_column :my_models, :date_column, :datetime, null: false

2

คุณไม่สามารถใช้ add_timestamps และ null: false ถ้าคุณมีระเบียนที่มีอยู่ดังนั้นนี่คือวิธีแก้ไข:

def change
  add_timestamps(:buttons, null: true)

  Button.find_each { |b| b.update(created_at: Time.zone.now, updated_at: Time.zone.now) }

  change_column_null(:buttons, :created_at, false)
  change_column_null(:buttons, :updated_at, false)
end
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.