Raylarda bir sütun türünü daha uzun dizelerle değiştirme


90

İlk migrasyonda, contentActiverecord dizgesini bir sütunda ilan ettim, onu annotate gem'e göre string (255) yaptı.

Uygulamayı postgres kullanan heroku'ya aktardıktan sonra, forma içerikte 255'ten daha uzun bir dizge girersem hata alıyorum

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

Sorun şu ki, bu içeriğin son derece uzun bir dizge içermesine ihtiyacım var (serbest metin, binlerce karakter olabilir)

  1. Pg hangi değişkeni (string bunun için uygun değil) kabul eder?
  2. Bu sütunun türünü değiştirmek için nasıl geçiş oluşturabilirim

Teşekkürler

Yanıtlar:


217

textUzunluk sınırı olmayan bir dizi istiyorsanız Rails ile kullanmalısınız . Bunun gibi bir göç:

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

işleri halletmeli. Bunun sonunda da isteyebilir :null => falseveya başka seçenekler olabilir .

stringAçık bir sınırı olmayan bir sütun kullandığınızda , Rails bir örtük ekler :limit => 255. Ancak kullanırsanız text, veritabanının desteklediği keyfi uzunlukta dize türünü alırsınız. PostgreSQL, varcharuzunluğu olmayan bir sütun kullanmanıza izin verir, ancak çoğu veritabanı bunun için ayrı bir tür kullanır ve Rails, varcharuzunluk olmadan bunu bilmez . Sen kullanmak zorunda textbir olsun Rails textsütun PostgreSQL. Orada bir tür sütun arasında PostgreSQL hiçbir fark textve tip bir varchar(fakat varchar(n) bir farklı). Ayrıca, PostgreSQL'in üstüne konuşlandırıyorsanız, :string(AKA varchar) kullanmak için hiçbir neden yoktur , veritabanı davranır textvevarchar(n)için ekstra uzunluk kısıtlamaları dışında dahili olarak aynı varchar(n); Yalnızca kullanmalısınız varchar(n)(AKA :stringharici kısıtlamayı varsa kolon boyutuna (örneğin 23 karakter uzunluğunda olacak şekilde 897 / B bu alanı 432 yazan bir hükümet biçimi olarak)).

Bir kenara, stringherhangi bir yerde bir sütun kullanıyorsanız , her zaman :limitbir sınır olduğunu kendinize hatırlatmak için belirtmelisiniz ve sınırın aşılmamasını sağlamak için modelde bir doğrulama yaptırmalısınız. Sınırı aşarsanız, PostgreSQL şikayet eder ve bir istisna oluşturur, MySQL dizeyi sessizce keser veya şikayet eder (sunucu yapılandırmasına bağlı olarak), SQLite olduğu gibi geçmesine izin verir ve diğer veritabanları başka bir şey yapar (muhtemelen şikayet eder) .

Ayrıca, aynı veritabanının (Heroku'da genellikle PostgreSQL olacak) üzerine geliştiriyor, test ediyor ve dağıtıyor olmalısınız, hatta veritabanı sunucusunun aynı sürümlerini bile kullanmalısınız. Veritabanları arasında ActiveRecord'un sizi engellemeyeceği (GROUP BY davranışı gibi) başka farklılıklar da vardır. Bunu zaten yapıyor olabilirsin ama yine de bahsetmeyi düşündüm.


Güncelleme : ActiveRecord'un daha yeni sürümleri varcharsınırsız olarak anlar , bu nedenle en azından PostgreSQL ile şunu söyleyebilirsiniz:

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

bir varchar(n)sütunu olarak değiştirmek için varchar. textve varcharPostgreSQL söz konusu olduğunda hala aynı şeydir, ancak bazı form oluşturucular bunları farklı şekilde ele varcharalır : bir <input type="text">oysa textbir çok satır alır <textarea>.


13
Mükemmel cevap. Bir not: Rails şu anda change_column'u değiştirme yöntemiyle desteklemiyor ( guides.rubyonrails.org/migrations.html#using-the-change-method ); bellek hizmet ederse, bunu yaparsanız geri dönüşü olmayan bir geçiş yaratırsınız. Yukarı / aşağı yöntemlerle eski usul şekilde yapmak daha iyidir.
poetmountain

@BourbonJockey: changeBir tür değişikliğini otomatik olarak tersine çeviremeyecek olması mantıklı geliyor ve Geçiş Kılavuzu "[değiştirme yöntemi] Yapıcı geçişleri yazmak için (sütun veya tablo eklemek) bu yöntem tercih edilir" ve change_columnisn ' Listede işaret ettiğiniz için haklı olduğunuzu düşünüyorum. up/ down(Üzerinde bir uyarı ile down) kullanmak için düzelttim , uyarılar için teşekkürler.
mu çok kısa

4
Diğer okuyucuların gelecekteki referansı için, Heroku'daki Postgres'te dizeden metne bu şekilde dönüştürmek veri kaybetmez.
Marina Martin

2
@Dennis: Belki "aynı veritabanını kullanarak geliştirmeli, test etmeli ve dağıtmalısınız" daha doğru olacaktır. Genel sorun, insanların (gülünç) Rails'in varsayılan SQLite kurulumunu kullanması ve başka bir şeyin üzerine konuşlandıklarında her şeyin parçalanmasıdır. PostgreSQL, Heroku'da hala varsayılan ve en yaygın seçenektir, değil mi?
mu çok kısa

3
Bir yan not olarak, Rails'in belirtilmemiş uzunluktaki alanların 255 karakter olması gerektiği varsayımı tuhaftır. Öyle değil kullanmak PostgreSQL gerekli textsınırsız uzunluğu elde etmek için sadece; sadece sınırsız kullanabilirsiniz varchar. Rails, bu garip sınırı PostgreSQL'i değil, dayatıyor.
Craig Ringer

8

Kabul edilen cevap mükemmel olsa da, benim gibi uzman olmayanlar için orijinal posterlerin 2. sorusu ile daha iyi ilgileneceğini umduğum bir cevabı buraya eklemek istedim.

  1. Bu sütunun türünü değiştirmek için nasıl geçiş oluşturabilirim

iskele geçişi oluşturmak

Konsolunuza yazarak değişikliğinizi tutmak için bir geçiş oluşturabilirsiniz (sadece tabletablo adınız columniçin ve sizin için sütun adınızı değiştirin)

rails generate migration change_table_column

Bu, Rails application / db / migrate / klasörünüzün içinde iskelet geçişi oluşturacaktır. Bu taşıma, taşıma kodunuz için bir yer tutucudur.

Mesela ben bir sütunun türünü değiştirmek için bir göç oluşturmak istediğiniz stringiçin textbir tablo olarak adlandırılan TodoItems içinde,:

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

Taşıma işleminizi yürütmek

Kodu girdikten sonra sütunu değiştirmek için sadece çalıştırın:

rake db:migrate

Geçişinizi uygulamak için. Bir hata yaparsanız, değişikliği her zaman şu şekilde geri döndürebilirsiniz:

rake db:rollack

Yukarı ve Aşağı yöntemleri

Yeni yöntem yerine kabul edilen yanıt referansları Upve Downyöntemler Change. Raylar 3.2 eski stil Yukarı ve Aşağı Yöntemler, yeni Değiştirme yöntemine göre birkaç avantaj sunduğundan. Yukarı ve Aşağı'dan kaçının ActiveRecord::IrreversibleMigration exception. Rails 4 piyasaya sürüldüğünden beri reversiblebu hatayı önlemek için kullanabilirsiniz :

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'in keyfini çıkarın :)

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.