Dodaj wartość domyślną do kolumny poprzez migrację

276

Jak dodać wartość domyślną do kolumny, która już istnieje podczas migracji?

Cała dokumentacja, którą mogę znaleźć, pokazuje, jak to zrobić, jeśli kolumna jeszcze nie istnieje, ale w tym przypadku tak jest.

Jon
źródło

Odpowiedzi:

352

Oto jak powinieneś to zrobić:

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

Ale niektóre bazy danych, takie jak PostgreSQL, nie aktualizują pola dla wcześniej utworzonych wierszy, więc upewnij się, że zaktualizowałeś pole manaul również podczas migracji.

Maurício Linhares
źródło
14
Jeśli potrzebujesz odwracalnych migracji, umieść to w upbloku, a nie w changebloku. Możesz zostawić downblok pusty. Nie przywróci pierwotnego stanu tabeli, ale migrację można przywrócić.
IAmNaN
1
Czy dzięki temu dane pozostaną nienaruszone?
Marco Prins
2
Na PostgreSQL tak, nie wiem, co stanie się z innymi bazami danych.
Maurício Linhares
1
Co masz na myśli mówiąc „upewnij się, że ręcznie zaktualizujesz pole podczas migracji”? Jak to zrobić?
David Argyle Thacker
7
Wypróbowałem to na PostgreSQL i zaktualizowałem wcześniej utworzone pola.
Aboozar Rajabi,
190
change_column_default :employees, :foreign, false
Gazza
źródło
1
@DenisLins Zgodziłem się z tobą, więc przeprowadziłem badania, aby dowiedzieć się, dlaczego tak nie jest, i okazuje się, że istnieje możliwość, że dany adapter bazy danych go nie obsługuje, ponieważ jest zaimplementowany na tym poziomie. Akceptowana odpowiedź jest nadal najbezpieczniejszym zakładem, dopóki nie zostanie zaimplementowana w modelu abstrakcyjnym. apidock.com/rails/ActiveRecord/ConnectionAdapters/…
natchiketa
5
Poza tym musisz określić from:a, to:jeśli chcesz, aby był odwracalny :)
radubogdan
5
Za pomocą fromi tozostał dodany w Railsach 5+ w tym zatwierdzeniu: github.com/rails/rails/pull/20018/files
Joshua Pinter
115

W przypadku Railsów 4+ użyjchange_column_default

def change
  change_column_default :table, :column, value
end
csi
źródło
1
Jest to szczególnie przydatne, jeśli masz migrację, która dodaje kolumnę i ustawia wartości domyślne dla istniejących rekordów. Na przykład: def change `add_column: foos,: name, default:" coś dla istniejących wartości "` `change_column_default: foos,: name, default:" "end
user1491929
2
Ta migracja ma dziwne zachowanie. W twoim przykładzie jest to nieodwracalne. edgeguides.rubyonrails.org/active_record_migrations.html zalecamy używanie go w ten sposób: change_column_default :products, :approved, from: true, to: false- ale to też nie działa.
Ilya Krigouzov
nie możesz tego cofnąć?
aldrien.h
Zwykle tak, dla prawie każdej klauzuli „Zmień”, ponieważ wszystkie poprzednie stany są zwykle jawne, takie jak obecność kolumny, jej typ itp. Zmianę można cofnąć, tak jak tam pokazano, i tylko wtedy, gdy istnieje poprzednio ważne jawne domyślne. Ponieważ często zdarza się, że wartości domyślne są niezdefiniowane, może to oznaczać problem.
Elindor,
48

Używanie def changeoznacza, że ​​powinieneś pisać migracje, które są odwracalne. I change_columnnie jest odwracalny. Możesz iść w górę, ale nie możesz zejść, ponieważ change_columnjest nieodwracalny.

Zamiast tego, chociaż może to być kilka dodatkowych linii, powinieneś użyć def upidef down

Więc jeśli masz kolumnę bez wartości domyślnej, powinieneś to zrobić, aby dodać wartość domyślną.

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

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

Lub jeśli chcesz zmienić wartość domyślną dla istniejącej kolumny.

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

def down
  change_column :users, :admin, :boolean, default: true
end
bfcoder
źródło
37

** Szyny 4.X + **

Począwszy od wersji Rails 4 nie można wygenerować migracji w celu dodania kolumny do tabeli z wartością domyślną . Poniższe kroki dodają nową kolumnę do istniejącej tabeli z wartością domyślną true lub false.

1. Uruchom migrację z wiersza polecenia, aby dodać nową kolumnę

$ rails generate migration add_columnname_to_tablename columnname:boolean

Powyższe polecenie doda nową kolumnę do twojej tabeli.

2. Ustaw nową wartość kolumny na PRAWDA / FAŁSZ, edytując nowy utworzony plik migracji.

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

** 3. Aby wprowadzić zmiany w tabeli bazy danych aplikacji, uruchom następującą komendę w terminalu **

$ rake db:migrate
Praveen George
źródło
Czym różni się to od szyn 3+ lub 2+?
Ruby Racer
2
Czy ktoś wie, czy zostało to włączone do Rails 5?
sambecker
9

Wykonać:

rails generate migration add_column_to_table column:boolean

Wygeneruje tę migrację:

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

Ustaw wartość dodaną dodając: default => 1

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

Biegać:

rake db: migracja

axeltaglia
źródło
2
Teraz domyślna wartość 1 nie jest dokładnie wartością logiczną;) Ten przykład dodaje nową kolumnę, zamiast zmieniać istniejącą kolumnę, co chciał osiągnąć OP
radiospiel
@radiospiel Właściwie to 1 też ma wartość logiczną :)
kinduff
Aby to zadziałało, musisz także utworzyć rekord w tabeli kluczy obcych o identyfikatorze 1 Key is not present in table error.
Obiecaj Preston
-50

Oto, co możesz zrobić:

class Profile < ActiveRecord::Base
  before_save :set_default_val

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

EDYCJA: ... ale najwyraźniej jest to błąd Świeżaka!

nowicjuszRailer
źródło
Lepiej jest ustawić wartość domyślną w schemacie vs jakobefore_save
rigelstpierre
6
Co za okropna sugestia
svelandiag,
zgodził się, to naprawdę okropne
Houcheng
3
ouch, masz dużo ciepła do zrobienia czegoś na poziomie modelu zamiast na poziomie bazy danych. -38 to legendarny wynik.
nurettin
1
co za debiutancki błąd ... ;-)
webaholik