Jak napisać migrację, aby zmienić nazwę modelu ActiveRecord i jego tabeli w Railsach?

408

Okropnie nazywam się i zdaję sobie sprawę, że w mojej aplikacji Rails jest lepszy zestaw nazw dla moich modeli.
Czy istnieje sposób użycia migracji do zmiany nazwy modelu i odpowiadającej mu tabeli?

Tylko czytać
źródło
11
Zasugerowałem dodanie „ActiveRecord” do tego pytania, aby poprawić dopasowania wyszukiwarek. Szukałem tego za pomocą „tabeli zmian nazw ActiveRecord”.
Landon Kuhn
6
Jeśli korzystasz z migracji, ten problem jest bardziej skomplikowany niż się wydaje. Wybrane rozwiązanie mówi, aby po prostu zmienić nazwę modelu, kontrolera itp. Po zmianie nazwy tabeli. Jeśli to zrobisz, wszystkie starsze migracje, które odnoszą się do twojego modelu pod jego starszą nazwą, zakończą się niepowodzeniem. Więc jeśli ktoś sklonuje twoje repozytorium i spróbuje uruchomić rake db:migrate, to się nie powiedzie. Możesz wrócić i zmienić te nazwy podczas migracji, ale to będzie bałagan. Lepiej jest po prostu stworzyć zupełnie nowy model niż zmienić jego nazwę.
andrew
4
@andrewhannigan: Czy nie masz sensu, jeśli ktoś klonuje twoje repozytorium i po prostu działa rake db:schema:load?
istrasci
3
@istrasci: absolutnie. W rzeczywistości rake db:migrateodradza się uruchamianie w celu skonfigurowania bazy danych od zera, właśnie ze względu na obawy wskazane przez andrew.
Giuseppe,

Odpowiedzi:

584

Oto przykład:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def self.up
    rename_table :old_table_name, :new_table_name
  end

  def self.down
    rename_table :new_table_name, :old_table_name
  end
end

Musiałem ręcznie zmienić nazwę pliku deklaracji modelu.

Edytować:

W Railsach 3.1 i 4 ActiveRecord::Migration::CommandRecorderumie odwrócić migracje tabeli zmian nazw, więc możesz to zrobić:

class RenameOldTableToNewTable < ActiveRecord::Migration
  def change
    rename_table :old_table_name, :new_table_name
  end 
end

(Nadal musisz przejść i ręcznie zmienić nazwę plików).

Tylko czytać
źródło
6
@mathee: tak, musisz to zmienić ręcznie lub za pomocą IDE, które może dokonać refaktoryzacji Ruby i zatwierdzić to w systemie kontroli wersji.
pupeno
13
git grep jest twoim przyjacielem. W tej chwili zmieniam nazwę działania na nawyk: git grep -i activitjest bardzo odkrywczy.
Felix Rabe
1
musisz także zmienić zawartość swojego kontrolera, prawda?
alemur
5
I nie zapomnij swoich tras. Rb!
Dan Herman
26
Ponadto, podobnie jak w heads-upie, chcesz użyć liczby mnogiej nazwy tabeli w wywołaniu rename_table.
Han
66

W Rails 4 wszystko, co musiałem zrobić, to zmiana def

def change
  rename_table :old_table_name, :new_table_name
end

Zaopiekowano się wszystkimi moimi indeksami. Nie musiałem ręcznie aktualizować indeksów, usuwając stare i dodając nowe.

I działa przy użyciu zmiany do zwiększania lub zmniejszania również w odniesieniu do indeksów.

bfcoder
źródło
47

Inne odpowiedzi i komentarze dotyczyły zmiany nazwy tabeli, zmiany nazwy pliku i grepowania w kodzie.

Chciałbym dodać jeszcze kilka zastrzeżeń:

Wykorzystajmy przykład z prawdziwego świata: przemianowanie modelu z „Merchant” na „Business”.

  • Nie zapomnij zmienić nazw zależnych tabel i modeli podczas tej samej migracji. Zmieniłem jednocześnie modele Merchant i MerchantStat na Business i BusinessStat. W przeciwnym razie musiałbym zrobić o wiele za dużo wybierania i wybierania podczas wyszukiwania i zamiany.
  • W przypadku innych modeli, które zależą od modelu za pomocą kluczy obcych, nazwy kolumn w kluczach obcych w innych tabelach będą pochodzić z oryginalnej nazwy modelu. Dlatego też będziesz chciał wykonać kilka wywołań zmiany nazwy na tych modelach zależnych. Na przykład musiałem zmienić nazwę kolumny „merchant_id” na „business_id” w różnych tabelach łączenia (dla relacji has_and_belongs_to_many) i innych tabelach zależnych (dla normalnych relacji has_one i has_many). W przeciwnym razie skończyłbym z kolumnami typu „business_stat.merchant_id” wskazującymi na „business.id”. Oto dobra odpowiedź na temat zmiany nazw kolumn.
  • Podczas grepowania pamiętaj, aby szukać wersji ciągów w liczbie pojedynczej, mnogiej, wielkiej, małej, a nawet WIELKIEJ (które mogą wystąpić w komentarzach).
  • Najlepiej jest szukać najpierw liczby mnogiej, a następnie pojedynczej. W ten sposób, jeśli masz nieregularną liczbę mnogą - na przykład u moich kupców :: przykład firm - możesz poprawić wszystkie nieregularne liczby mnogie. W przeciwnym razie możesz skończyć na przykład z „biznesem” (3 s) jako stanem pośrednim, co spowoduje jeszcze więcej wyszukiwania i zamiany.
  • Nie zastępuj na ślepo każdego zdarzenia. Jeśli nazwy modeli kolidują ze wspólnymi terminami programowania, wartościami w innych modelach lub treściami tekstowymi w twoich widokach, możesz być zbyt przesadny. W moim przykładzie chciałem zmienić nazwę mojego modelu na „Biznes”, ale nadal nazywam ich „kupcami” w treści w moim interfejsie użytkownika. Miałem także rolę „handlowca” dla moich użytkowników w CanCan - to zamieszanie między rolą kupca a modelem handlowca spowodowało, że zmieniłem nazwę tego modelu.
armchairdj
źródło
26

Musisz także wymienić swoje indeksy:

class RenameOldTableToNewTable< ActiveRecord:Migration
  def self.up
    remove_index :old_table_name, :column_name
    rename_table :old_table_name, :new_table_name
    add_index :new_table_name, :column_name
  end 

  def self.down
    remove_index :new_table_name, :column_name
    rename_table :new_table_name, :old_table_name
    add_index :old_table_name, :column_name
  end
end

I zmień nazwę plików itp. Ręcznie, jak opisują inne odpowiedzi tutaj.

Zobacz: http://api.rubyonrails.org/classes/ActiveRecord/Migration.html

Upewnij się, że możesz cofnąć i przejść do przodu po napisaniu tej migracji. Może to być trudne, jeśli coś się nie powiedzie i utkniesz w migracji, która próbuje wywołać coś, co już nie istnieje. Najlepiej usuń całą bazę danych i zacznij od nowa, jeśli nie możesz wycofać. Pamiętaj więc, że może być konieczne wykonanie kopii zapasowej.

Ponadto: sprawdź, czy w schema_db nie ma żadnych istotnych nazw kolumn w innych tabelach zdefiniowanych przez has_ ​​lub należy_do, czy coś. Prawdopodobnie będziesz też musiał je edytować.

I w końcu robienie tego bez zestawu testów regresji byłoby szalone.

Rimian
źródło
11
Jeśli chodzi o migracje w wersji 4.0.0.beta1, nie trzeba ręcznie aktualizować indeksów. AR sam go aktualizuje.
freemanoid,
1

Możesz wykonać to polecenie: rails gigration rename_ {old_table_name} do {new_table_name}

po edycji pliku i dodaniu tego kodu do zmiany metody

rename_table: {old_table_name},: {new_table_name}

Mouhamadou Bamba Mboup
źródło