Tambahkan nilai default ke kolom melalui migrasi


276

Bagaimana cara menambahkan nilai default ke kolom yang sudah ada melalui migrasi?

Semua dokumentasi yang saya temukan menunjukkan kepada Anda cara melakukannya jika kolomnya belum ada tetapi dalam kasus ini memang ada.

Jawaban:


352

Inilah cara Anda harus melakukannya:

change_column :users, :admin, :boolean, :default => false

Tetapi beberapa database, seperti PostgreSQL, tidak akan memperbarui bidang untuk baris yang sebelumnya dibuat, jadi pastikan Anda memperbarui bidang manaully pada migrasi juga.


14
Jika Anda membutuhkan migrasi yang dapat dibalikkan, letakkan ini di dalam upblok dan bukan di changeblok. Anda dapat membiarkan downblok kosong. Itu tidak akan mengembalikan tabel ke kondisi semula tetapi migrasi dapat dibatalkan.
IAmNaN

1
Apakah ini akan menjaga data tetap utuh?
Marco Prins

2
Di PostgreSQL, ya, saya tidak tahu apa yang akan terjadi pada database lain.
Maurício Linhares

1
Apa maksud Anda ketika Anda mengatakan "pastikan Anda memperbarui bidang secara manual tentang migrasi"? Bagaimana seseorang melakukan itu?
David Argyle Thacker

7
Saya mencobanya di PostgreSQL dan memperbarui bidang yang dibuat sebelumnya.
Aboozar Rajabi

190
change_column_default :employees, :foreign, false

1
@DenisLins Saya setuju dengan Anda, jadi saya melakukan riset untuk mencari tahu mengapa hal itu tidak terjadi, dan ternyata ada kemungkinan adaptor database tertentu tidak mendukungnya, karena diterapkan pada tingkat itu. Jawaban yang diterima masih merupakan taruhan teraman sampai diterapkan dalam model abstrak. apidock.com/rails/ActiveRecord/ConnectionAdapters/…
natchiketa

5
Selain itu, Anda perlu menentukan from:dan to:jika Anda ingin menjadi reversibel :)
radubogdan

5
Menggunakan fromdan toditambahkan dalam Rails 5+ dalam komit ini: github.com/rails/rails/pull/20018/files
Joshua Pinter

115

Untuk Rails 4+ , gunakanchange_column_default

def change
  change_column_default :table, :column, value
end

1
Ini bagus terutama jika Anda memiliki migrasi yang menambahkan kolom dan menetapkan default untuk catatan yang ada. Misalnya: def change `add_column: foos,: name, default:" sesuatu untuk nilai yang ada "` `change_column_default: foos,: name, default:" "`end
user1491929

2
Migrasi ini memiliki perilaku yang aneh. Dalam contoh Anda, itu tidak dapat dipulihkan. edgeguides.rubyonrails.org/active_record_migrations.html merekomendasikan untuk menggunakannya dengan cara ini: change_column_default :products, :approved, from: true, to: false- tetapi tidak berfungsi juga.
Ilya Krigouzov

tidak dapat mengembalikan menggunakan itu?
aldrien.h

Biasanya begitu ya, untuk hampir semua klausa "Ubah", karena semua status sebelumnya biasanya eksplisit, seperti keberadaan kolom, jenisnya, dll. Perubahan dapat diputar kembali seperti yang ditunjukkan di sana jika dan hanya jika ada default eksplisit yang valid sebelumnya. Karena standarnya tidak terdefinisi, Anda mungkin memiliki masalah di sana.
Elindor

48

Menggunakan def changeberarti Anda harus menulis migrasi yang dapat dibalik. Dan change_columntidak bisa dibalik. Anda dapat naik tetapi Anda tidak bisa turun, karena change_columntidak dapat dipulihkan.

Sebaliknya, meskipun mungkin beberapa baris tambahan, Anda harus menggunakan def updandef down

Jadi jika Anda memiliki kolom tanpa nilai default, maka Anda harus melakukan ini untuk menambahkan nilai default.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: nil
end

Atau jika Anda ingin mengubah nilai default untuk kolom yang ada.

def up
  change_column :users, :admin, :boolean, default: false
end

def down
  change_column :users, :admin, :boolean, default: true
end

37

** Rails 4.X + **

Pada Rails 4 Anda tidak dapat menghasilkan migrasi untuk menambahkan kolom ke tabel dengan nilai default, Langkah-langkah berikut menambahkan kolom baru ke tabel yang ada dengan nilai default benar atau salah.

1. Jalankan migrasi dari baris perintah untuk menambahkan kolom baru

$ rails generate migration add_columnname_to_tablename columnname:boolean

Perintah di atas akan menambahkan kolom baru di tabel Anda.

2. Tetapkan nilai kolom baru ke TRUE / FALSE dengan mengedit file migrasi baru yang dibuat.

class AddColumnnameToTablename < ActiveRecord::Migration
  def change
    add_column :table_name, :column_name, :boolean, default: false
  end
end

** 3. Untuk membuat perubahan ke tabel database aplikasi Anda, jalankan perintah berikut di terminal **

$ rake db:migrate

Apa bedanya dengan rails 3+ atau 2+?
Ruby Racer

2
Apakah ada yang tahu jika ini telah dimasukkan ke dalam Rails 5?
sambecker

9

Menjalankan:

rails generate migration add_column_to_table column:boolean

Ini akan menghasilkan migrasi ini:

class AddColumnToTable < ActiveRecord::Migration
  def change
    add_column :table, :column, :boolean
  end
end

Tetapkan nilai default menambahkan: default => 1

add_column: table,: column,: boolean,: default => 1

Lari:

rake db: bermigrasi


2
Sekarang nilai default 1 bukanlah boolean;) Selain itu, contoh ini menambahkan kolom baru, alih-alih mengubah kolom yang ada, yang ingin dicapai oleh OP
radiospiel

@radiospiel Sebenarnya, 1 juga boolean :)
kinduff

Anda juga perlu membuat catatan di tabel kunci asing dengan ID 1 agar ini berfungsi, untuk menghindari Key is not present in table error.
Janji Preston

-50

Inilah yang dapat Anda lakukan:

class Profile < ActiveRecord::Base
  before_save :set_default_val

  def set_default_val
    self.send_updates = 'val' unless self.send_updates
  end
end

EDIT: ... tapi ini kesalahan Rookie!


Lebih baik jika Anda menetapkan default dalam skema vs sebagaibefore_save
rigelstpierre

6
Saran yang mengerikan
svelandiag

setuju, ini benar-benar mengerikan
Houcheng

3
Aduh, Anda punya banyak panas untuk melakukan sesuatu di tingkat model daripada tingkat basis data. -38 adalah skor legendaris.
nurettin

1
apa kesalahan pemula ... ;-)
webaholik
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.