Migracja szyn do kolumny zmiany

327

Mamy script/generate migration add_fieldname_to_tablename fieldname:datatypeskładnię dodawania nowych kolumn do modelu.

Czy w tym samym wierszu mamy skrypt / generator do zmiany typu danych kolumny? Czy powinienem pisać SQL bezpośrednio w mojej waniliowej migracji?

Chcę zmienić kolumnę z datetimena date.

papdel
źródło

Odpowiedzi:

548

Myślę, że to powinno zadziałać.

change_column :table_name, :column_name, :date
Alex Korban
źródło
13
@b_ayan: O ile mi wiadomo, jedynymi magicznymi słowami w nazwach migracji są „dodaj” i „usuń”.
Alex Korban
1
Coś w rodzaju szyn noob tutaj, ale… rozumiem odpowiedź, ale nie komentarze do tej odpowiedzi. Docenia się wyjaśnienia :)
Alan H.,
7
Podczas tworzenia migracji nadajesz jej nazwę (np. Add_fieldname_to_tablename w powyższym pytaniu). Jeśli zaczyna się od „dodaj” lub „usuń”, wówczas migracja zostanie automatycznie wypełniona kodem, aby dodać lub usunąć kolumny, co oszczędza pisanie tego kodu.
Alex Korban
6
Warto również pamiętać, że powinieneś zastąpić zwykłe changedziałanie oddzielnymi upi downdziałaniami, podobnie jak change_columnnieodwracalna migracja i pojawi się błąd, jeśli będziesz musiał cofnąć.
DaveStephens
1
@QPaysTaxes up powinien zawierać to, co chcesz zmienić kolumnę z i na, a down powinien zawierać sposób na odwrócenie tej zmiany.
DaveStephens
98

Możesz także użyć bloku, jeśli masz wiele kolumn do zmiany w tabeli.

Przykład:

change_table :table_name do |t|
  t.change :column_name, :column_type, {options}
end

Więcej informacji znajduje się w dokumentacji interfejsu API klasy Table .

Jan
źródło
88

Nie wiem, czy możesz wykonać migrację z wiersza polecenia, aby to wszystko zrobić, ale możesz utworzyć nową migrację, a następnie edytować migrację, aby wykonać tę taksówkę.

Jeśli tablename to nazwa tabeli, nazwa pola to nazwa pola i chcesz zmienić od daty do daty, możesz napisać migrację, aby to zrobić.

Możesz utworzyć nową migrację za pomocą:

rails g migration change_data_type_for_fieldname

Następnie edytuj migrację, aby użyć tabeli zmian:

class ChangeDataTypeForFieldname < ActiveRecord::Migration
  def self.up
    change_table :tablename do |t|
      t.change :fieldname, :date
    end
  end
  def self.down
    change_table :tablename do |t|
      t.change :fieldname, :datetime
    end
  end
end

Następnie uruchom migrację:

rake db:migrate
Ryan
źródło
32

Jak znalazłem w poprzednich odpowiedziach, potrzebne są trzy kroki, aby zmienić typ kolumny:

Krok 1:

Wygeneruj nowy plik migracji przy użyciu tego kodu:

rails g migration sample_name_change_column_type

Krok 2:

Przejdź do /db/migratefolderu i edytuj utworzony plik migracji. Istnieją dwa różne rozwiązania.

  1. def change
        change_column(:table_name, :column_name, :new_type)
    end
    

2)

    def up
        change_column :table_name, :column_name, :new_type
    end

    def down
        change_column :table_name, :column_name, :old_type
    end

Krok 3:

Nie zapomnij wykonać tej komendy:

rake db:migrate

Przetestowałem to rozwiązanie dla Rails 4 i działa dobrze.

Aboozar Rajabi
źródło
1
W kroku 2 pierwszy nie powiedzie się po uruchomieniu rake db: rollback, polecam sprawdzenie drugiego
Feuda
Czy istnieje konwencja szyn, która pozwala mniej więcej wszystko zrobić podczas generowania pliku migracji bez przechodzenia do niego, a następnie jego edycji?
BKSpurgeon
@BKSpurgeon Tak, sprawdź dokumentację tutaj: edgeguides.rubyonrails.org/active_record_migrations.html
Aboozar Rajabi
12

Z szynami 5

Z prowadnic Rails :

Jeśli chcesz, aby migracja zrobiła coś, czego Active Record nie potrafi cofnąć, możesz użyć reversible:

class ChangeTablenameFieldname < ActiveRecord::Migration[5.1]
  def change
    reversible do |dir|
      change_table :tablename do |t|
        dir.up   { t.change :fieldname, :date }
        dir.down { t.change :fieldname, :datetime }
      end
    end
  end
end
Pan Tao
źródło
8

Po prostu wygeneruj migrację:

rails g migration change_column_to_new_from_table_name

Zaktualizuj migrację w następujący sposób:

class ClassName < ActiveRecord::Migration
  change_table :table_name do |table|
    table.change :column_name, :data_type
  end
end

i w końcu

rake db:migrate
Vivek Sharma
źródło
2

Kolejny sposób zmiany typu danych za pomocą migracji

krok 1: Musisz usunąć nazwę pola uszkodzonego typu danych podczas migracji

dawny:

rails g migration RemoveFieldNameFromTableName field_name:data_type

Nie zapomnij podać typu danych dla swojego pola

Krok 2: Teraz możesz dodać pole z poprawnym typem danych

dawny:

rails g migration AddFieldNameToTableName field_name:data_type

To wszystko, teraz twoja tabela zostanie dodana z poprawnym polem typu danych, Szczęśliwego kodowania ruby ​​!!

prasanthrubyist
źródło
2

Wszystko to przy założeniu, że typ danych kolumny ma domyślną konwersję dla wszelkich istniejących danych. Natknąłem się na kilka sytuacji, w których istniejące dane, powiedzmy, Stringmożna domyślnie przekonwertować na nowy typ danych, powiedzmy Date.

W tej sytuacji warto wiedzieć, że możesz tworzyć migracje z konwersjami danych. Osobiście lubię umieszczać je w moim pliku modelu, a następnie usuwać je po migracji wszystkich schematów bazy danych i ich stabilizacji.

/app/models/table.rb
  ...
  def string_to_date
    update(new_date_field: date_field.to_date)
  end

  def date_to_string
    update(old_date_field: date_field.to_s)
  end
  ...
    def up
        # Add column to store converted data
        add_column :table_name, :new_date_field, :date
        # Update the all resources
        Table.all.each(&:string_to_date)
        # Remove old column
        remove_column :table_name, :date_field
        # Rename new column
        rename_column :table_name, :new_date_field, :date_field
    end

    # Reversed steps does allow for migration rollback
    def down
        add_column :table_name, :old_date_field, :string
        Table.all.each(&:date_to_string)
        remove_column :table_name, :date_field
        rename_column :table_name, :old_date_field, :date_field
    end
Sebastian Scholl
źródło
0

Aby uzupełnić odpowiedzi w przypadku edycji wartości domyślnej :

W konsoli szyn:

rails g migration MigrationName

W migracji:

  def change
    change_column :tables, :field_name, :field_type, default: value
  end

Będzie wyglądać jak :

  def change
    change_column :members, :approved, :boolean, default: true
  end
Gregdebrick
źródło