Null olabilecek bir sütunu Rails geçişinde null edilemeyen olarak nasıl değiştirebilirim?


188

Önceki bir taşıma işleminde bir tarih sütunu oluşturdum ve boş bırakılabilir olarak ayarladım. Şimdi bunu geçersiz kılınmayacak şekilde değiştirmek istiyorum. Bu veritabanında boş satırlar olduğunu varsayarak bunu nasıl yapabilirim? Şu anda null olup olmadıklarını bu sütunları Time.now olarak ayarlamakla sorun değil.

Yanıtlar:


204

Bir taşıma işleminde yaparsanız, büyük olasılıkla şu şekilde yapabilirsiniz:

# 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
Sadece bir not, çünkü bu beni geliştirici veritabanımı bozdu. Aksine bu gibi açık karma sözdizimini kullanın: MyModel.update_all({:date_column => Time.now}, {:date_column => nil}). Orijinal formunuzdaki sorgu, tüm modellerimin alanda nil değerine sahip olmasını sağladı.
dimitarvp

Güncelleme için teşekkürler. Bu yanıtı yazdığımda durumun böyle olmadığını biliyorum ama o sırada hangi Ruby veya RoR sürümünü kullandığımı hatırlayamıyorum.
DanneManne

1
Bu geçişte 'yukarı' / 'aşağı' yöntemini kullandınız mı, yoksa taşıma işlemindeki basit değişiklik yöntemini kullanabilir misiniz?
EE33

2
change(1) için bir yöntem bu yüzden, bu durum için uygun değildir update_allyöntem migrate ve potansiyel bir Geri alma hem de çalıştırılcak. Bu en kötü şey olmayabilir, çünkü (2) göçün potansiyel bir geri dönüşte sütunun neyin değiştirildiğini bilmesinin bir yolu yoktur. Bu durumda upve ile yapışırdım down.
DanneManne

2
İlgilenen herkes için cevabım bunu tek bir adımda nasıl yapacağınızı gösteriyor.
Rick Smith

167

Rails 4'te bu daha iyi (DRYer) bir çözümdür:

change_column_null :my_models, :date_column, false

Bu NULLsütundaki değerlerle hiçbir kayıt bulunmadığından emin olmak için, NULLdeğerleri olan kayıtlar için kullanılacak varsayılan değer olan dördüncü bir parametre iletebilirsiniz :

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

4
Bu tablo zaten boş değerlere sahip olduğunda sorunlara neden olur. Cevabımı gör
Rick Smith

5
3.2 sürümünde de mevcuttur. Değerin null olduğu varsayılan değeri ayarlamak için de 4. parametresi vardır.
toxaq

1
Artı 1 change_column_null. Ancak Rick Smith'in yukarıdaki yorumu çok geçerli bir duruma işaret ediyor.
0112

Boş değerleri güncelleme sorgusu eklenecek şekilde güncellendi. 4th parametresi (varsayılan değer), yalnızca gelecekteki kayıtlar için de varsayılana sahip olmak istediğinizde kullanışlıdır.
mrbrdo

3
Aslında, Rails 4.2 belgelerine göre, 4. parametre gelecekteki kayıtlar için varsayılan bir değer ayarlamaz: "Yöntem, mevcut + NULL + 'ları başka bir değerle değiştirmek için isteğe bağlı bir dördüncü bağımsız değişkeni kabul eder. Lütfen dördüncü bağımsız değişkenin ayarlanmadığını unutmayın sütununun varsayılan değeri. "
Mike Fischer

70

Rails 4 (diğer Rails 4 cevaplarında sorun var):

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

İçinde NULL değerleri olan bir sütunun NULL değerine izin vermeyecek şekilde değiştirilmesi sorunlara neden olur. Bu tam olarak geliştirme kurulumunda iyi çalışacak ve daha sonra LIVE üretiminize dağıtmaya çalıştığınızda çökecek kod türüdür . Önce NULL değerlerini geçerli bir şeye değiştirmeli ve sonra NULL değerlerine izin vermemelisiniz. 4. değer change_column_nulltam olarak bunu yapar. Daha fazla ayrıntı için belgelere bakın.

Ayrıca, genellikle yeni bir nesne oluşturduğumda alanın değerini belirtmem gerekmeyecek şekilde alan için varsayılan bir değer ayarlamayı tercih ederim. Ben de bunu yapmak için yorum kodu dahil.


3
Rails 4 için, bu, yorum yapılan varsayılan ayar da dahil olmak üzere en doğru ve eksiksiz yanıttır.
Mike Fischer

4
Bir tabloya yeni bir sütun ekliyorsanız ve null için yeni değerler eklemek istiyorsanız, ancak sütun için varsayılan bir değer eklemek istemiyorsanız, bunu geçişinizde yapabilirsiniz: add_column :users, :admin, :stringo zamanchange_column_null(:admin, :string, false, "new_value_for_existing_records")
colsen

34

Değeri olan bir change_columnifadeye sahip bir taşıma oluşturun :default =>.

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

Bakınız: change_column

Veritabanı motoruna bağlı olarak kullanmanız gerekebilir change_column_null


1
Bu benim için çalıştı. MySql'i yerel olarak kullanma. Ne zaman itti ve Heroku (Postgres) app koştu bir boş yazarken null değildi sütun üzerinde crapped - haklı olarak çok. Yalnızca "change_column_null" çalışır, MySql'de "change_column ...: null => false" kullanamaz. Teşekkürler.
rtfminc

1
change_column_null'dan sonra göçünüz neydi
js111

1
Postges daha sıkı MySQL - gerektirir olacağını beklenir change_column_null.
jessecurry

3
@rtfminc Gelişmelerde ve üretimde aynı veritabanı motorunu kullanmanızı şiddetle tavsiye ediyorum, çünkü kenar durumlarda çok fazla sorun yaşanmıyor.
yagooar


3

Olarak raylar 4.02+ göre dokümanlar gibi bir yöntem yoktur update_all2 argüman. Bunun yerine bu kod kullanılabilir:

# 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

Kayıtlarınız varsa add_timestamps ve null: false komutlarını kullanamazsınız. İşte çözüm:

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