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.down„ zawsze 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.