การเปลี่ยนประเภทคอลัมน์เป็นสตริงที่ยาวขึ้นในราง


90

ในการย้ายข้อมูลครั้งแรกฉันประกาศในคอลัมน์contentเป็นสตริง Activerecord ทำให้เป็นสตริง (255) ตามคำอธิบายประกอบอัญมณี

หลังจากที่ฉันดันแอปไปที่ heroku ซึ่งใช้ postgres หากฉันป้อนในแบบฟอร์มในเนื้อหาสตริงที่ยาวกว่า 255 ฉันได้รับข้อผิดพลาด

PGError: ERROR: value too long for type character varying(255)

ปัญหาคือฉันต้องการให้เนื้อหานั้นมีสตริงที่ยาวมากบางที (ข้อความอิสระอาจเป็นตัวอักษรหลายพันตัว)

  1. ตัวแปรใด (สตริงไม่เหมาะสมสำหรับสิ่งนี้) pg จะยอมรับหรือไม่?
  2. ฉันจะสร้างการย้ายข้อมูลเพื่อแทนที่ประเภทของคอลัมน์นั้นได้อย่างไร

ขอบคุณ

คำตอบ:


217

คุณควรใช้textกับ Rails หากคุณต้องการสตริงที่ไม่จำกัดความยาว การโยกย้ายเช่นนี้:

def up
  change_column :your_table, :your_column, :text
end
def down
  # This might cause trouble if you have strings longer
  # than 255 characters.
  change_column :your_table, :your_column, :string
end

ควรแยกแยะสิ่งต่างๆ คุณอาจต้องการ:null => falseหรือตัวเลือกอื่น ๆ ในตอนท้ายด้วย

เมื่อคุณใช้stringคอลัมน์โดยไม่ต้องมีขีด จำกัด :limit => 255ที่ชัดเจนทางรถไฟจะเพิ่มโดยปริยาย แต่ถ้าคุณใช้textคุณจะได้รับสตริงความยาวใดก็ได้ที่ฐานข้อมูลรองรับ PostgreSQL อนุญาตให้คุณใช้varcharคอลัมน์ที่ไม่มีความยาว แต่ฐานข้อมูลส่วนใหญ่ใช้ประเภทแยกต่างหากสำหรับสิ่งนั้นและ Rails ไม่รู้เกี่ยวกับvarcharหากไม่มีความยาว คุณต้องใช้textใน Rails เพื่อรับtextคอลัมน์ใน PostgreSQL มีความแตกต่างใน PostgreSQL ระหว่างคอลัมน์ชนิดไม่ได้textและเป็นหนึ่งในประเภทvarchar( แต่varchar(n) เป็นที่แตกต่างกัน) นอกจากนี้หากคุณกำลังปรับใช้กับ PostgreSQL ก็ไม่มีเหตุผลที่จะใช้:string(AKA varchar) เลยฐานข้อมูลจะถือว่าtextและvarchar(n)ภายในเหมือนกันยกเว้นข้อ จำกัด ด้านความยาวพิเศษสำหรับvarchar(n); คุณควรใช้varchar(n)(AKA :string) เฉพาะในกรณีที่คุณมีข้อ จำกัด ภายนอก (เช่นแบบฟอร์มรัฐบาลที่ระบุว่าฟิลด์ 432 ในแบบฟอร์ม 897 / B จะมีความยาว 23 อักขระ) กับขนาดคอลัมน์

นอกจากนี้หากคุณใช้stringคอลัมน์ที่ใดก็ได้คุณควรระบุ:limitเพื่อเตือนตัวเองเสมอว่ามีขีด จำกัด และคุณควรมีการตรวจสอบความถูกต้องในแบบจำลองเพื่อให้แน่ใจว่าจะไม่เกินขีด จำกัด หากคุณใช้งานเกินขีด จำกัด PostgreSQL จะบ่นและยกข้อยกเว้น MySQL จะตัดสตริงหรือบ่นอย่างเงียบ ๆ (ขึ้นอยู่กับการกำหนดค่าเซิร์ฟเวอร์) SQLite จะปล่อยให้มันผ่านไปตามที่เป็นอยู่และฐานข้อมูลอื่นจะทำอย่างอื่น (อาจจะบ่น) .

นอกจากนี้คุณควรพัฒนาทดสอบและปรับใช้ฐานข้อมูลเดียวกัน (ซึ่งโดยปกติจะเป็น PostgreSQL ที่ Heroku) คุณควรใช้เซิร์ฟเวอร์ฐานข้อมูลเวอร์ชันเดียวกันด้วยซ้ำ มีความแตกต่างอื่น ๆ ระหว่างฐานข้อมูล (เช่นลักษณะการทำงานของ GROUP BY) ที่ ActiveRecord จะไม่ป้องกันคุณ คุณอาจจะทำสิ่งนี้อยู่แล้ว แต่ฉันคิดว่าฉันจะพูดถึงมันอยู่ดี


อัปเดต : ActiveRecord เวอร์ชันใหม่กว่าสามารถเข้าใจได้varcharโดยไม่มีขีด จำกัด ดังนั้นอย่างน้อย PostgreSQL ก็สามารถพูดได้ว่า:

change_column :your_table, :your_column, :string, limit: nil

ที่จะเปลี่ยนคอลัมน์varchar(n) และยังคงมีสิ่งที่เหมือนกันเท่าที่ PostgreSQL เป็นห่วง แต่บางสร้างรูปแบบที่จะปฏิบัติต่อพวกเขาแตกต่างกัน: ได้รับในขณะที่ได้รับหลายสายvarchartextvarcharvarchar<input type="text">text<textarea>


13
คำตอบที่ดี หมายเหตุหนึ่ง: ขณะนี้ Rails ไม่รองรับ change_column ด้วยวิธีการเปลี่ยนแปลง ( guide.rubyonrails.org/migrations.html#using-the-change-method ); หากหน่วยความจำทำงานคุณจะสร้างการย้ายที่ไม่สามารถย้อนกลับได้หากคุณทำเช่นนั้น ดีกว่าที่จะทำแบบเก่าด้วยวิธีการขึ้น / ลง
poetmountain

@BourbonJockey: มันสมเหตุสมผลที่changeจะไม่สามารถย้อนกลับการเปลี่ยนแปลงประเภทโดยอัตโนมัติได้และคู่มือการย้ายข้อมูลบอกว่า "[วิธีการเปลี่ยนแปลง] วิธีนี้เหมาะสำหรับการเขียนการย้ายข้อมูลเชิงสร้างสรรค์ (การเพิ่มคอลัมน์หรือตาราง)" และchange_columnisn ' ในรายการที่คุณชี้ไปฉันคิดว่าคุณพูดถูก ฉันแก้ไขให้ใช้up/ down(โดยมีข้อแม้down) ขอบคุณสำหรับการแจ้งเตือน
สั้นเกินไป

4
สำหรับการอ้างอิงในอนาคตของผู้อ่านคนอื่น ๆ การแปลงจากสตริงเป็นข้อความใน Postgres บน Heroku ในลักษณะนี้จะไม่สูญเสียข้อมูล
Marina Martin

2
@ เดนนิส: บางที "คุณควรพัฒนาทดสอบและปรับใช้โดยใช้ฐานข้อมูลเดียวกัน" จะแม่นยำกว่า ปัญหาปกติคือผู้คนใช้การตั้งค่า SQLite เริ่มต้น (ไร้สาระ) Rails และสิ่งต่าง ๆ จะแตกออกเมื่อนำไปใช้กับอย่างอื่น PostgreSQL ยังคงเป็นตัวเลือกเริ่มต้นและเป็นที่นิยมมากที่สุดใน Heroku ไม่ใช่หรือ?
สั้นเกินไป

3
หมายเหตุด้านข้างสมมติฐานของ Rails ที่ว่าความยาวที่ไม่ระบุควรเป็น 255 อักขระนั้นแปลก มันเป็นไม่จำเป็นใน PostgreSQL ใช้textเพียงเพื่อให้ได้ความยาวไม่ จำกัด ; varcharคุณก็สามารถใช้ข้อ จำกัด Rails กำลังกำหนดขีด จำกัด แปลก ๆ นี้ไม่ใช่ PostgreSQL
Craig Ringer

8

แม้ว่าคำตอบที่ได้รับการยอมรับนั้นยอดเยี่ยม แต่ฉันต้องการเพิ่มคำตอบที่นี่ซึ่งหวังว่าจะจัดการกับคำถามของโปสเตอร์ต้นฉบับตอนที่ 2 ได้ดีขึ้นสำหรับผู้ที่ไม่ใช่ผู้เชี่ยวชาญเช่นฉัน

  1. ฉันจะสร้างการย้ายข้อมูลเพื่อแทนที่ประเภทของคอลัมน์นั้นได้อย่างไร

สร้างการโยกย้ายแบบนั่งร้าน

คุณสามารถสร้างการย้ายข้อมูลเพื่อระงับการเปลี่ยนแปลงของคุณโดยพิมพ์ในคอนโซลของคุณ (เพียงแค่แทนที่tableสำหรับชื่อตารางของคุณและcolumnสำหรับคุณชื่อคอลัมน์)

rails generate migration change_table_column

สิ่งนี้จะสร้างการย้ายโครงกระดูกภายในคุณ Rails application / db / migrate / folder การย้ายข้อมูลนี้เป็นตัวยึดสำหรับรหัสการย้ายข้อมูลของคุณ

ตัวอย่างเช่นฉันต้องการสร้างการโยกย้ายเพื่อเปลี่ยนประเภทของคอลัมน์จากstringเป็นtextในตารางที่เรียกว่า TodoItems:

class ChangeTodoItemsDescription < ActiveRecord::Migration
  def change
     # enter code here
     change_column :todo_items, :description, :text
  end
end

เรียกใช้การย้ายข้อมูลของคุณ

เมื่อคุณป้อนรหัสเพื่อเปลี่ยนคอลัมน์แล้วให้เรียกใช้:

rake db:migrate

เพื่อใช้การย้ายข้อมูลของคุณ หากคุณทำข้อผิดพลาดคุณสามารถยกเลิกการเปลี่ยนแปลงได้ตลอดเวลาโดย:

rake db:rollack

วิธีการขึ้นและลง

การอ้างอิงคำตอบUpและDownวิธีการที่ยอมรับแทนที่จะเป็นChangeวิธีการที่ใหม่กว่า เนื่องจากราง3.2 วิธีการขึ้นและลงแบบเก่านำเสนอข้อดีบางประการเหนือวิธีการเปลี่ยนแปลงที่ใหม่กว่า 'ขึ้นและลง' ActiveRecord::IrreversibleMigration exceptionหลีกเลี่ยง ตั้งแต่การเปิดตัวRails 4คุณสามารถใช้reversibleเพื่อหลีกเลี่ยงข้อผิดพลาดนี้:

class ChangeProductsPrice < ActiveRecord::Migration
  def change
    reversible do |dir|
      change_table :products do |t|
        dir.up   { t.change :price, :string }
        dir.down { t.change :price, :integer }
      end
    end
  end
end

สนุกกับ Rails :)

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