Jak mogę zmienić nazwę kolumny bazy danych podczas migracji Ruby on Rails?


Odpowiedzi:


2308
rename_column :table, :old_column, :new_column

Aby to zrobić, prawdopodobnie będziesz chciał utworzyć osobną migrację. (Zmień nazwę, FixColumnNamejak chcesz.):

script/generate migration FixColumnName
# creates  db/migrate/xxxxxxxxxx_fix_column_name.rb

Następnie edytuj migrację, aby wykonać swoją wolę:

# db/migrate/xxxxxxxxxx_fix_column_name.rb
class FixColumnName < ActiveRecord::Migration
  def self.up
    rename_column :table_name, :old_column, :new_column
  end

  def self.down
    # rename back if you need or do something else or do nothing
  end
end

W przypadku Rails 3.1 użyj:

Chociaż nadal obowiązują metody upi down, Rails 3.1 otrzymuje changemetodę, która „wie, jak przeprowadzić migrację bazy danych i odwrócić ją, gdy migracja zostanie wycofana bez potrzeby zapisywania oddzielnej metody wyłączania”.

Aby uzyskać więcej informacji, zobacz „ Migracje aktywnych rekordów ”.

rails g migration FixColumnName

class FixColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

Jeśli zdarzy się, że masz całą grupę kolumn do zmiany nazwy lub coś, co wymagałoby powtarzania nazwy tabeli w kółko:

rename_column :table_name, :old_column1, :new_column1
rename_column :table_name, :old_column2, :new_column2
...

Możesz użyć tego, change_tableaby zachować trochę porządek:

class FixColumnNames < ActiveRecord::Migration
  def change
    change_table :table_name do |t|
      t.rename :old_column1, :new_column1
      t.rename :old_column2, :new_column2
      ...
    end
  end
end

Więc db:migratejak zwykle lub jakkolwiek zajmujesz się swoją działalnością.


W przypadku szyn 4:

Podczas tworzenia Migrationzmiany nazwy kolumny Rails 4 generuje changemetodę zamiast upi downjak wspomniano w powyższej sekcji. Wygenerowana changemetoda to:

$ > rails g migration ChangeColumnName

który utworzy plik migracji podobny do:

class ChangeColumnName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

24
self.down powinno zawsze być przeciwieństwem self.up, więc „jeśli potrzebujesz lub zrób coś innego lub nic nie rób” nie jest tak naprawdę zalecane. Po prostu zrób: rename_column: table_name,: new_column,: old_column
Luke Griffiths

3
Chociaż normalną praktyką jest cofanie tego, co zrobiłeś self.up, nie powiedziałbym, że self.downzawsze powinno być odwrotnie”. W zależy od kontekstu migracji. Samo umieszczenie „przeciwieństwa” może nie być „właściwym” spadkiem migracji.
teraz

23
W Rails 3.1 można zastąpić def self.upi def self.downze def changei to będzie wiedzieć, jak cofnąć.
Turadg,

2
Turadg - * przez większość czasu będzie wiedział, jak wycofać. Uważam, że changemetoda nie jest pełnym dowodem, więc zwykle używaj upi downmetod do złożonych migracji.
JellyFishBoy,

6
Czy zmiana nazwy usuwa indeks?
Sung Cho

68

Moim zdaniem w tym przypadku lepiej użyć rake db:rollback, a następnie edytować migrację i ponownie uruchomić rake db:migrate.

Jeśli jednak w kolumnie znajdują się dane, których nie chcesz stracić, użyj rename_column.


34
Nawet w „jednym zespole”, jeśli masz uruchomionych wiele wystąpień aplikacji, powiedzmy w różnych środowiskach lub na wielu komputerach itp., Zarządzanie edytowanymi migracjami jest dużym problemem. I tylko edytować migrację gdybym tylko stworzył go i zrozumiał, że to nie tak, i nie uruchamiać go dosłownie wszędzie jeszcze innego.
Yetanotherjosh

1
Potem musiałem zrestartować serwer.
Muhammad Hewedy,

7
Tej techniki należy używać tylko w sytuacji, gdy zmiany nie zostały jeszcze scalone z gałęzią produkcji, a inne nie są zależne od trwałości danych. W większości przypadków produkcyjnych NIE jest to preferowana metoda.
Collin Graves

4
nigdy nie rób takich rzeczy.
new2cpp

4
Chciałbym powiedzieć mojemu zespołowi: „Migracje są bezpłatne” Koszt edycji migracji, która została wypuszczona na wolność, jest wysoki: kiedyś spędziłem kilka godzin, zastanawiając się, dlaczego mój kod nie działa, zanim zdałem sobie sprawę z innego członka zespołu wróciłem i zredagowałem migrację, którą już uruchomiłem. Więc nie edytuj istniejącej migracji, użyj nowej, aby zmienić schemat, ponieważ ... ... 'Migracje są bezpłatne!' (nie jest to do końca prawda, ale ma sens)
TerryS

31

Jeśli kolumna jest już zapełniona danymi i jest uruchomiona w produkcji, zaleciłbym podejście krok po kroku, aby uniknąć przestojów w produkcji podczas oczekiwania na migrację.

Najpierw utworzę migrację bazy danych, aby dodać kolumny z nowymi nazwami i wypełnić je wartościami ze starej nazwy kolumny.

class AddCorrectColumnNames < ActiveRecord::Migration
  def up
    add_column :table, :correct_name_column_one, :string
    add_column :table, :correct_name_column_two, :string

    puts 'Updating correctly named columns'
    execute "UPDATE table_name SET correct_name_column_one = old_name_column_one, correct_name_column_two = old_name_column_two"
    end
  end

  def down
    remove_column :table, :correct_name_column_one
    remove_column :table, :correct_name_column_two
  end
end

Następnie dokonałbym właśnie tej zmiany i pchnąłbym ją do produkcji.

git commit -m 'adding columns with correct name'

Potem, gdy zatwierdzenie zostanie wprowadzone do produkcji, zacznę działać.

Production $ bundle exec rake db:migrate

Następnie zaktualizowałbym wszystkie widoki / kontrolery, które odwoływały się do starej nazwy kolumny do nowej nazwy kolumny. Uruchom mój zestaw testów i zatwierdź tylko te zmiany. (Po upewnieniu się, że działa lokalnie i najpierw przejściu wszystkich testów!)

git commit -m 'using correct column name instead of old stinky bad column name'

Potem zmusiłbym to zobowiązanie do produkcji.

W tym momencie możesz usunąć oryginalną kolumnę bez obawy o jakiekolwiek przestoje związane z samą migracją.

class RemoveBadColumnNames < ActiveRecord::Migration
  def up
    remove_column :table, :old_name_column_one
    remove_column :table, :old_name_column_two
  end

  def down
    add_column :table, :old_name_column_one, :string
    add_column :table, :old_name_column_two, :string
  end
end

Następnie wypchnij najnowszą migrację do produkcji i uruchom ją bundle exec rake db:migratew tle.

Zdaję sobie sprawę, że jest to trochę bardziej zaangażowane w proces, ale wolę to zrobić niż mieć problemy z migracją produkcji.


2
Podoba mi się myślenie za tym i dałbym +1 twojemu repsonse, ale aktualizacja danych zajęłaby bardzo dużo czasu, ponieważ przechodzi przez szyny i wykonuje jeden wiersz na raz. Migracja byłaby wykonywana znacznie szybciej przy użyciu surowych instrukcji SQL, aby zaktualizować kolumny o prawidłowych nazwach. Na przykład w pierwszym skrypcie migracji bazy danych, po dodaniu zduplikowanych nazw kolumn, execute "Update table_name set correct_name_column_one = old_name_column_one"
Gui Weinmann

1
@ mr.ruh.roh ^ Całkowicie się zgadzam, powinienem to napisać w pierwszej kolejności. Edytowałem, aby odzwierciedlić jedną wydajną instrukcję SQL. Dzięki za kontrolę poczytalności.
Paul Pettengill,

2
Co dzieje się z wpisami pomiędzy przejściem do nowej tabeli a aktualizacją kodu w celu użycia nowej tabeli? Czy nie mogłeś pozostawić potencjalnie niemigrowanych danych?
Stefan Dorunga

1
chociaż jest to „bezpieczna” odpowiedź, czuję, że jest niekompletna. Wiele osób mówi, że tego nie robią - dlaczego? trwałość danych. I to jest ważne. Prawdopodobnie najmniej bolesnym sposobem na osiągnięcie celu jest utworzenie nowych pól, wypełnienie ich danymi ze starych kolumn, dostosowanie kontrolerów. Jeśli chcesz usunąć stare kolumny, z pewnością będziesz musiał edytować widoki. Kosztem ich utrzymania jest dodatkowa przestrzeń db i trochę zdublowanego wysiłku w kontrolerze. Kompromisy są zatem jasne.
Jerome


18

Uruchom poniższe polecenie, aby utworzyć plik migracji:

rails g migration ChangeHasedPasswordToHashedPassword

Następnie w pliku wygenerowanym w db/migratefolderze napisz rename_columnjak poniżej:

class ChangeOldCoulmnToNewColumn < ActiveRecord::Migration
  def change
     rename_column :table_name, :hased_password, :hashed_password
  end
end

14

Z interfejsu API:

rename_column(table_name, column_name, new_column_name)

Zmienia nazwę kolumny, ale utrzymuje typ i treść pozostaje taka sama.


12

Niektóre wersje Ruby on Rails obsługują metodę migracji w górę / w dół, a jeśli masz migrację w górę / w dół, to:

def up
    rename_column :table_name, :column_old_name, :column_new_name
end

def down
    rename_column :table_name, :column_new_name, :column_old_name
end

Jeśli masz changemetodę migracji, to:

def change
    rename_column :table_name, :column_old_name, :column_new_name
end

Aby uzyskać więcej informacji, możesz przenieść: Ruby on Rails - Migrations lub Active Record Migrations .


11

Jeśli twój kod nie jest współdzielony z innym, najlepszym rozwiązaniem jest dokonanie rake db:rollback edycji nazwy kolumny podczas migracji irake db:migrate . Otóż ​​to

Możesz napisać kolejną migrację, aby zmienić nazwę kolumny

 def change
    rename_column :table_name, :old_name, :new_name
  end

Otóż ​​to.


rake db:rollbackto świetna sugestia. Ale jak powiedziałeś, tylko jeśli migracja nie została jeszcze przesunięta.
danielricecodes

9

Alternatywnie, jeśli nie jesteś żonaty z ideą migracji, istnieje atrakcyjny klejnot dla ActiveRecord, który będzie automatycznie obsługiwał zmiany nazw dla ciebie, styl Datamapper. Wszystko, co musisz zrobić, to zmienić nazwę kolumny w swoim modelu (i upewnij się, że umieściłeś Model.auto_upgrade! Na dole swojego modelu.rb) i viola! Baza danych jest aktualizowana na bieżąco.

https://github.com/DAddYE/mini_record

Uwaga: Aby zapobiec konfliktom, musisz nuke db / schema.rb

Wciąż w fazie beta i oczywiście nie dla wszystkich, ale wciąż przekonujący wybór (obecnie używam go w dwóch nietrywialnych aplikacjach produkcyjnych bez problemów)


8

Jeśli musisz zmienić nazwy kolumn, musisz utworzyć symbol zastępczy, aby uniknąć błędu duplikatu nazwy kolumny . Oto przykład:

class SwitchColumns < ActiveRecord::Migration
  def change
    rename_column :column_name, :x, :holder
    rename_column :column_name, :y, :x
    rename_column :column_name, :holder, :y
  end
end

7

Jeśli obecne dane nie są dla Ciebie ważne, możesz po prostu usunąć oryginalną migrację, używając:

rake db:migrate:down VERSION='YOUR MIGRATION FILE VERSION HERE'

Bez cudzysłowów wprowadź zmiany w oryginalnej migracji i ponownie uruchom migrację w górę, wykonując:

rake db:migrate

6

Po prostu utwórz nową migrację, a w bloku użyj rename_columnjak poniżej.

rename_column :your_table_name, :hased_password, :hashed_password

6

W przypadku Ruby on Rails 4:

def change
    rename_column :table_name, :column_name_old, :column_name_new
end

5

Ręcznie możemy użyć poniższej metody:

Możemy edytować migrację ręcznie, jak:

  • otwarty app/db/migrate/xxxxxxxxx_migration_file.rb

  • Zaktualizuj hased_passworddohashed_password

  • Uruchom poniższe polecenie

    $> rake db:migrate:down VERSION=xxxxxxxxx

Następnie usunie migrację:

$> rake db:migrate:up VERSION=xxxxxxxxx

Spowoduje to dodanie migracji wraz ze zaktualizowaną zmianą.


nie będzie to bezpieczne, ponieważ możesz stracić dane - jeśli kolumna jest już aktywna. ale można zrobić dla nowej kolumny i / lub tabeli.
Tejas Patel,

5

Wygeneruj plik migracji:

rails g migration FixName

# Tworzy db / migrate / xxxxxxxxxx.rb

Edytuj migrację, aby wykonać swoją wolę.

class FixName < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

5

Biegać rails g migration ChangesNameInUsers (lub jakkolwiek chcesz to nazwać)

Otwórz właśnie utworzony plik migracji i dodaj ten wiersz w metodzie (pomiędzy def changei end):

rename_column :table_name, :the_name_you_want_to_change, :the_new_name

Zapisz plik i uruchom rake db:migratew konsoli

Sprawdź swoje schema.db, aby zobaczyć, czy nazwa rzeczywiście się zmieniła w bazie danych!

Mam nadzieję że to pomoże :)


5

Spójrzmy prawdzie w KISS . Wystarczy trzy proste kroki. Poniższe działa dla Railsów 5.2 .

1. Utwórz migrację

  • rails g migration RenameNameToFullNameInStudents

  • rails g RenameOldFieldToNewFieldInTableName- w ten sposób jest całkowicie jasne dla opiekunów bazy kodu później. (użyj liczby mnogiej jako nazwy tabeli).

2. Edytuj migrację

# I prefer to explicitly write thew górę w anddółmethods.

# ./db/migrate/20190114045137_rename_name_to_full_name_in_students.rb

class RenameNameToFullNameInStudents < ActiveRecord::Migration[5.2]
  def up
    # rename_column :table_name, :old_column, :new_column
    rename_column :students, :name, :full_name
  end

  def down
            # Note that the columns are reversed
    rename_column :students, :full_name, :name
  end
end

3. Uruchom migracje

rake db:migrate

I startujesz w wyścigach!


4
$:  rails g migration RenameHashedPasswordColumn
invoke  active_record
      create    db/migrate/20160323054656_rename_hashed_password_column.rb

Otwórz ten plik migracji i zmodyfikuj go jak poniżej (Podaj oryginał table_name)

class  RenameHashedPasswordColumn < ActiveRecord::Migration
  def change
    rename_column :table_name, :hased_password, :hashed_password
  end
end

4
 def change
    rename_column :table_name, :old_column_name, :new_column_name
  end

3

Wygeneruj migrację Ruby on Rails :

$:> rails g migration Fixcolumnname

Wstaw kod do pliku migracji (XXXXXfixcolumnname.rb) :

class Fixcolumnname < ActiveRecord::Migration
  def change
    rename_column :table_name, :old_column, :new_column
  end
end

2

Otwórz konsolę Ruby on Rails i wprowadź:

ActiveRecord::Migration.rename_column :tablename, :old_column, :new_column

2

Możesz to zrobić na dwa sposoby:

  1. W tym typie automatycznie uruchamia jego kod zwrotny podczas wycofywania.

    def change
      rename_column :table_name, :old_column_name, :new_column_name
    end
  2. Do tego typu uruchamia metodę „up” kiedy rake db:migratei uruchamia metodę „down”, gdy rake db:rollback:

    def self.up
      rename_column :table_name, :old_column_name, :new_column_name
    end
    
    def self.down
      rename_column :table_name,:new_column_name,:old_column_name
    end

2

Jestem na szynach 5.2 i próbuję zmienić nazwę kolumny na urządzeniu użytkownika.

rename_columnnieco pracował dla mnie, ale liczba pojedyncza :table_namerzucił „tabeli użytkownika nie znaleziono” błąd. Liczba mnoga zadziałała dla mnie.

rails g RenameAgentinUser

Następnie zmień plik migracji na ten:

rename_column :users, :agent?, :agent

Gdzie: agent? to stara nazwa kolumny.


0

Aktualizacja - bliskim kuzynem create_table jest change_table, służący do zmiany istniejących tabel. Jest on używany w podobny sposób do create_table, ale obiekt przekazany do bloku zna więcej sztuczek. Na przykład:

class ChangeBadColumnNames < ActiveRecord::Migration
  def change
    change_table :your_table_name do |t|
      t.rename :old_column_name, :new_column_name
    end
  end
end

Ten sposób jest bardziej wydajny, jeśli robimy to z innymi metodami modyfikacji, takimi jak: usuń / dodaj indeks / usuń indeks / dodaj kolumnę, np. Możemy zrobić dalej, jak:

# Rename
t.rename :old_column_name, :new_column_name
# Add column
t.string :new_column
# Remove column
t.remove :removing_column
# Index column
t.index :indexing_column
#...

0

Po prostu wygeneruj migrację za pomocą polecenia

rails g migration rename_hased_password

Po tej edycji migracji dodaj następujący wiersz w metodzie zmiany

rename_column :table, :hased_password, :hashed_password

To powinno załatwić sprawę.


0

Zmiany w migracji Rails 5

na przykład:

szyny g model Student student_name: string wiek: liczba całkowita

jeśli chcesz zmienić kolumnę nazwa_ studenta jako nazwę

Uwaga: - jeśli nie uruchomisz szyny db: migruj

Możesz wykonać następujące kroki

szyny d model Student student_name: string wiek: liczba całkowita

Spowoduje to usunięcie wygenerowanego pliku migracji. Teraz możesz poprawić nazwę kolumny

szyny g model Nazwa ucznia: wiek wiek: liczba całkowita

Jeśli przeprowadziłeś migrację (rails db: migrate), wykonaj następujące opcje, aby zmienić nazwę kolumny

migracja rails g RemoveStudentNameFromStudent student_name: string

szyny g migracja AddNameToStudent name: string


Czy nie powinno być: rails g migration RemoveStudentNameFromStudentS student_name:string(uczniowie są w liczbie mnogiej)?
BKSpurgeon

Jest to również niebezpieczne: nazwa kolumny nie jest zmieniana, ale całkowicie usuwana, a następnie czytana. Co stanie się z danymi? To może nie być to, czego użytkownik będzie chciał.
BKSpurgeon
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.